mirror of
https://github.com/minio/minio.git
synced 2025-11-21 10:16:03 -05:00
revert browser newux changes (#5714)
This commit is contained in:
@@ -23,7 +23,7 @@ export const DeleteObjectConfirmModal = ({
|
||||
}) => (
|
||||
<ConfirmModal
|
||||
show={true}
|
||||
icon="zmdi zmdi-alert-octagon"
|
||||
icon="fa fa-exclamation-triangle mci-red"
|
||||
text="Are you sure you want to delete?"
|
||||
sub="This cannot be undone!"
|
||||
okText="Delete"
|
||||
|
||||
107
browser/app/js/objects/ObjectActions.js
Normal file
107
browser/app/js/objects/ObjectActions.js
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Minio Cloud Storage (C) 2018 Minio, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react"
|
||||
import { connect } from "react-redux"
|
||||
import { Dropdown } from "react-bootstrap"
|
||||
import ShareObjectModal from "./ShareObjectModal"
|
||||
import DeleteObjectConfirmModal from "./DeleteObjectConfirmModal"
|
||||
import * as objectsActions from "./actions"
|
||||
import {
|
||||
SHARE_OBJECT_EXPIRY_DAYS,
|
||||
SHARE_OBJECT_EXPIRY_HOURS,
|
||||
SHARE_OBJECT_EXPIRY_MINUTES
|
||||
} from "../constants"
|
||||
|
||||
export class ObjectActions extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
showDeleteConfirmation: false
|
||||
}
|
||||
}
|
||||
shareObject(e) {
|
||||
e.preventDefault()
|
||||
const { object, shareObject } = this.props
|
||||
shareObject(
|
||||
object.name,
|
||||
SHARE_OBJECT_EXPIRY_DAYS,
|
||||
SHARE_OBJECT_EXPIRY_HOURS,
|
||||
SHARE_OBJECT_EXPIRY_MINUTES
|
||||
)
|
||||
}
|
||||
deleteObject() {
|
||||
const { object, deleteObject } = this.props
|
||||
deleteObject(object.name)
|
||||
}
|
||||
showDeleteConfirmModal(e) {
|
||||
e.preventDefault()
|
||||
this.setState({ showDeleteConfirmation: true })
|
||||
}
|
||||
hideDeleteConfirmModal() {
|
||||
this.setState({
|
||||
showDeleteConfirmation: false
|
||||
})
|
||||
}
|
||||
render() {
|
||||
const { object, showShareObjectModal } = this.props
|
||||
return (
|
||||
<Dropdown id={`obj-actions-${object.name}`}>
|
||||
<Dropdown.Toggle noCaret className="fia-toggle" />
|
||||
<Dropdown.Menu>
|
||||
<a
|
||||
href=""
|
||||
className="fiad-action"
|
||||
onClick={this.shareObject.bind(this)}
|
||||
>
|
||||
<i className="fa fa-copy" />
|
||||
</a>
|
||||
<a
|
||||
href=""
|
||||
className="fiad-action"
|
||||
onClick={this.showDeleteConfirmModal.bind(this)}
|
||||
>
|
||||
<i className="fa fa-trash" />
|
||||
</a>
|
||||
</Dropdown.Menu>
|
||||
{showShareObjectModal && <ShareObjectModal object={object} />}
|
||||
{this.state.showDeleteConfirmation && (
|
||||
<DeleteObjectConfirmModal
|
||||
deleteObject={this.deleteObject.bind(this)}
|
||||
hideDeleteConfirmModal={this.hideDeleteConfirmModal.bind(this)}
|
||||
/>
|
||||
)}
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
object: ownProps.object,
|
||||
showShareObjectModal: state.objects.shareObject.show
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
shareObject: (object, days, hours, minutes) =>
|
||||
dispatch(objectsActions.shareObject(object, days, hours, minutes)),
|
||||
deleteObject: object => dispatch(objectsActions.deleteObject(object))
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ObjectActions)
|
||||
@@ -19,23 +19,37 @@ import { connect } from "react-redux"
|
||||
import humanize from "humanize"
|
||||
import Moment from "moment"
|
||||
import ObjectItem from "./ObjectItem"
|
||||
import ObjectActions from "./ObjectActions"
|
||||
import * as actionsObjects from "./actions"
|
||||
import { getCheckedList } from "./selectors"
|
||||
|
||||
export const ObjectContainer = ({ object, downloadObject }) => {
|
||||
export const ObjectContainer = ({
|
||||
object,
|
||||
checkedObjectsCount,
|
||||
downloadObject
|
||||
}) => {
|
||||
let props = {
|
||||
name: object.name,
|
||||
contentType: object.contentType,
|
||||
size: humanize.filesize(object.size),
|
||||
lastModified: Moment(object.lastModified).format("lll")
|
||||
}
|
||||
if (checkedObjectsCount == 0) {
|
||||
props.actionButtons = <ObjectActions object={object} />
|
||||
}
|
||||
return <ObjectItem {...props} onClick={() => downloadObject(object.name)} />
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
checkedObjectsCount: getCheckedList(state).length
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
downloadObject: object => dispatch(actionsObjects.downloadObject(object))
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(undefined, mapDispatchToProps)(ObjectContainer)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ObjectContainer)
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
*/
|
||||
|
||||
import React from "react"
|
||||
import classNames from "classnames"
|
||||
import { connect } from "react-redux"
|
||||
import humanize from "humanize"
|
||||
import Moment from "moment"
|
||||
import { getDataType } from "../mime"
|
||||
import * as actions from "./actions"
|
||||
import { getCheckedList } from "./selectors"
|
||||
@@ -29,20 +30,13 @@ export const ObjectItem = ({
|
||||
checked,
|
||||
checkObject,
|
||||
uncheckObject,
|
||||
actionButtons,
|
||||
onClick
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={classNames({
|
||||
objects__row: true,
|
||||
"objects__row--directory": getDataType(name, contentType) == "folder"
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className="objects__column objects__column--select"
|
||||
data-object-type={getDataType(name, contentType)}
|
||||
>
|
||||
<div className="objects__select">
|
||||
<div className={"fesl-row"} data-type={getDataType(name, contentType)}>
|
||||
<div className="fesl-item fesl-item-icon">
|
||||
<div className="fi-select">
|
||||
<input
|
||||
type="checkbox"
|
||||
name={name}
|
||||
@@ -51,10 +45,11 @@ export const ObjectItem = ({
|
||||
checked ? uncheckObject(name) : checkObject(name)
|
||||
}}
|
||||
/>
|
||||
<i />
|
||||
<i className="fis-icon" />
|
||||
<i className="fis-helper" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="objects__column objects__column--name">
|
||||
<div className="fesl-item fesl-item-name">
|
||||
<a
|
||||
href="#"
|
||||
onClick={e => {
|
||||
@@ -65,10 +60,9 @@ export const ObjectItem = ({
|
||||
{name}
|
||||
</a>
|
||||
</div>
|
||||
<div className="objects__column objects__column--size">{size}</div>
|
||||
<div className="objects__column objects__column--date">
|
||||
{lastModified}
|
||||
</div>
|
||||
<div className="fesl-item fesl-item-size">{size}</div>
|
||||
<div className="fesl-item fesl-item-modified">{lastModified}</div>
|
||||
<div className="fesl-item fesl-item-actions">{actionButtons}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
101
browser/app/js/objects/ObjectsBulkActions.js
Normal file
101
browser/app/js/objects/ObjectsBulkActions.js
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Minio Cloud Storage (C) 2018 Minio, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react"
|
||||
import { connect } from "react-redux"
|
||||
import classNames from "classnames"
|
||||
import * as actions from "./actions"
|
||||
import { getCheckedList } from "./selectors"
|
||||
import DeleteObjectConfirmModal from "./DeleteObjectConfirmModal"
|
||||
|
||||
export class ObjectsBulkActions extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
showDeleteConfirmation: false
|
||||
}
|
||||
}
|
||||
deleteChecked() {
|
||||
const { deleteChecked } = this.props
|
||||
deleteChecked()
|
||||
this.hideDeleteConfirmModal()
|
||||
}
|
||||
hideDeleteConfirmModal() {
|
||||
this.setState({
|
||||
showDeleteConfirmation: false
|
||||
})
|
||||
}
|
||||
render() {
|
||||
const { checkedObjectsCount, downloadChecked, clearChecked } = this.props
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
"list-actions" +
|
||||
classNames({
|
||||
" list-actions-toggled": checkedObjectsCount > 0
|
||||
})
|
||||
}
|
||||
>
|
||||
<span className="la-label">
|
||||
<i className="fa fa-check-circle" /> {checkedObjectsCount} Objects
|
||||
selected
|
||||
</span>
|
||||
<span className="la-actions pull-right">
|
||||
<button id="download-checked" onClick={downloadChecked}>
|
||||
{" "}
|
||||
Download all as zip{" "}
|
||||
</button>
|
||||
</span>
|
||||
<span className="la-actions pull-right">
|
||||
<button
|
||||
id="delete-checked"
|
||||
onClick={() => this.setState({ showDeleteConfirmation: true })}
|
||||
>
|
||||
{" "}
|
||||
Delete selected{" "}
|
||||
</button>
|
||||
</span>
|
||||
<i
|
||||
className="la-close fa fa-times"
|
||||
id="close-bulk-actions"
|
||||
onClick={clearChecked}
|
||||
/>
|
||||
{this.state.showDeleteConfirmation && (
|
||||
<DeleteObjectConfirmModal
|
||||
deleteObject={this.deleteChecked.bind(this)}
|
||||
hideDeleteConfirmModal={this.hideDeleteConfirmModal.bind(this)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
checkedObjectsCount: getCheckedList(state).length
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
downloadChecked: () => dispatch(actions.downloadCheckedObjects()),
|
||||
clearChecked: () => dispatch(actions.resetCheckedList()),
|
||||
deleteChecked: () => dispatch(actions.deleteCheckedObjects())
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ObjectsBulkActions)
|
||||
@@ -25,55 +25,59 @@ export const ObjectsHeader = ({
|
||||
sortLastModifiedOrder,
|
||||
sortObjects
|
||||
}) => (
|
||||
<div className="objects__row objects__header hidden-xs">
|
||||
<div
|
||||
className="objects__column objects__column--name"
|
||||
id="sort-by-name"
|
||||
onClick={() => sortObjects("name")}
|
||||
data-sort="name"
|
||||
>
|
||||
Name
|
||||
<i
|
||||
className={classNames({
|
||||
objects__sort: true,
|
||||
zmdi: true,
|
||||
"zmdi-sort-desc": sortNameOrder,
|
||||
"zmdi-sort-asc": !sortNameOrder
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="objects__column objects__column--size"
|
||||
id="sort-by-size"
|
||||
onClick={() => sortObjects("size")}
|
||||
data-sort="size"
|
||||
>
|
||||
Size
|
||||
<i
|
||||
className={classNames({
|
||||
objects__sort: true,
|
||||
zmdi: true,
|
||||
"zmdi-sort-amount-desc": sortSizeOrder,
|
||||
"zmdi-sort-amount-asc": !sortSizeOrder
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="objects__column objects__column--date"
|
||||
id="sort-by-last-modified"
|
||||
onClick={() => sortObjects("last-modified")}
|
||||
data-sort="last-modified"
|
||||
>
|
||||
Last Modified
|
||||
<i
|
||||
className={classNames({
|
||||
objects__sort: true,
|
||||
zmdi: true,
|
||||
"zmdi-sort-amount-desc": sortLastModifiedOrder,
|
||||
"zmdi-sort-amount-asc": !sortLastModifiedOrder
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<div className="feb-container">
|
||||
<header className="fesl-row" data-type="folder">
|
||||
<div className="fesl-item fesl-item-icon" />
|
||||
<div
|
||||
className="fesl-item fesl-item-name"
|
||||
id="sort-by-name"
|
||||
onClick={() => sortObjects("name")}
|
||||
data-sort="name"
|
||||
>
|
||||
Name
|
||||
<i
|
||||
className={classNames({
|
||||
"fesli-sort": true,
|
||||
fa: true,
|
||||
"fa-sort-alpha-desc": sortNameOrder,
|
||||
"fa-sort-alpha-asc": !sortNameOrder
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="fesl-item fesl-item-size"
|
||||
id="sort-by-size"
|
||||
onClick={() => sortObjects("size")}
|
||||
data-sort="size"
|
||||
>
|
||||
Size
|
||||
<i
|
||||
className={classNames({
|
||||
"fesli-sort": true,
|
||||
fa: true,
|
||||
"fa-sort-amount-desc": sortSizeOrder,
|
||||
"fa-sort-amount-asc": !sortSizeOrder
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="fesl-item fesl-item-modified"
|
||||
id="sort-by-last-modified"
|
||||
onClick={() => sortObjects("last-modified")}
|
||||
data-sort="last-modified"
|
||||
>
|
||||
Last Modified
|
||||
<i
|
||||
className={classNames({
|
||||
"fesli-sort": true,
|
||||
fa: true,
|
||||
"fa-sort-numeric-desc": sortLastModifiedOrder,
|
||||
"fa-sort-numeric-asc": !sortLastModifiedOrder
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<div className="fesl-item fesl-item-actions" />
|
||||
</header>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ import React from "react"
|
||||
import ObjectContainer from "./ObjectContainer"
|
||||
import PrefixContainer from "./PrefixContainer"
|
||||
|
||||
const Aux = props => props.children
|
||||
|
||||
export const ObjectsList = ({ objects }) => {
|
||||
const list = objects.map(object => {
|
||||
if (object.name.endsWith("/")) {
|
||||
@@ -28,7 +26,7 @@ export const ObjectsList = ({ objects }) => {
|
||||
return <ObjectContainer object={object} key={object.name} />
|
||||
}
|
||||
})
|
||||
return <Aux>{list}</Aux>
|
||||
return <div>{list}</div>
|
||||
}
|
||||
|
||||
export default ObjectsList
|
||||
|
||||
@@ -15,25 +15,22 @@
|
||||
*/
|
||||
|
||||
import React from "react"
|
||||
import classNames from "classnames"
|
||||
import { connect } from "react-redux"
|
||||
import InfiniteScroll from "react-infinite-scroller"
|
||||
import * as actionsObjects from "./actions"
|
||||
import ObjectsList from "./ObjectsList"
|
||||
|
||||
const Aux = props => props.children
|
||||
|
||||
export class ObjectsListContainer extends React.Component {
|
||||
render() {
|
||||
const { objects, isTruncated, currentBucket, loadObjects } = this.props
|
||||
return (
|
||||
<Aux>
|
||||
<div className="feb-container">
|
||||
<InfiniteScroll
|
||||
pageStart={0}
|
||||
loadMore={() => loadObjects(true)}
|
||||
hasMore={isTruncated}
|
||||
useWindow={false}
|
||||
element="div"
|
||||
className="objects__lists"
|
||||
useWindow={true}
|
||||
initialLoad={false}
|
||||
>
|
||||
<ObjectsList objects={objects} />
|
||||
@@ -44,7 +41,7 @@ export class ObjectsListContainer extends React.Component {
|
||||
>
|
||||
<span>Loading...</span>
|
||||
</div>
|
||||
</Aux>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,11 @@ import React from "react"
|
||||
import ObjectsHeader from "./ObjectsHeader"
|
||||
import ObjectsListContainer from "./ObjectsListContainer"
|
||||
|
||||
const Aux = props => props.children
|
||||
|
||||
export const ObjectsSection = () => (
|
||||
<Aux>
|
||||
<div>
|
||||
<ObjectsHeader />
|
||||
<ObjectsListContainer />
|
||||
</Aux>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default ObjectsSection
|
||||
|
||||
@@ -32,21 +32,25 @@ export const Path = ({ currentBucket, currentPrefix, selectPrefix }) => {
|
||||
dirPath.push(dir)
|
||||
let dirPath_ = dirPath.join("/") + "/"
|
||||
return (
|
||||
<a key={i} href="" onClick={e => onPrefixClick(e, dirPath_)}>
|
||||
{dir}
|
||||
</a>
|
||||
<span key={i}>
|
||||
<a href="" onClick={e => onPrefixClick(e, dirPath_)}>
|
||||
{dir}
|
||||
</a>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<nav className="path hidden-xs">
|
||||
<a onClick={e => onPrefixClick(e, "")} href="">
|
||||
{currentBucket}
|
||||
</a>
|
||||
<h2>
|
||||
<span className="main">
|
||||
<a onClick={e => onPrefixClick(e, "")} href="">
|
||||
{currentBucket}
|
||||
</a>
|
||||
</span>
|
||||
{path}
|
||||
</nav>
|
||||
</h2>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -38,21 +38,11 @@ export class ShareObjectModal extends React.Component {
|
||||
}
|
||||
}
|
||||
this.expiryRange = {
|
||||
days: {
|
||||
min: 0,
|
||||
max: 7
|
||||
},
|
||||
hours: {
|
||||
min: 0,
|
||||
max: 23
|
||||
},
|
||||
minutes: {
|
||||
min: 0,
|
||||
max: 59
|
||||
}
|
||||
days: { min: 0, max: 7 },
|
||||
hours: { min: 0, max: 23 },
|
||||
minutes: { min: 0, max: 59 }
|
||||
}
|
||||
}
|
||||
|
||||
updateExpireValue(param, inc) {
|
||||
let expiry = Object.assign({}, this.state.expiry)
|
||||
|
||||
@@ -78,16 +68,14 @@ export class ShareObjectModal extends React.Component {
|
||||
expiry
|
||||
})
|
||||
|
||||
const { shareObjectDetails: { object }, shareObject } = this.props
|
||||
shareObject(object, expiry.days, expiry.hours, expiry.minutes)
|
||||
const { object, shareObject } = this.props
|
||||
shareObject(object.name, expiry.days, expiry.hours, expiry.minutes)
|
||||
}
|
||||
|
||||
onUrlCopied() {
|
||||
const { showCopyAlert, hideShareObject } = this.props
|
||||
showCopyAlert("Link copied to clipboard!")
|
||||
hideShareObject()
|
||||
}
|
||||
|
||||
render() {
|
||||
const { shareObjectDetails, shareObject, hideShareObject } = this.props
|
||||
return (
|
||||
@@ -97,34 +85,32 @@ export class ShareObjectModal extends React.Component {
|
||||
onHide={hideShareObject}
|
||||
bsSize="small"
|
||||
>
|
||||
<Modal.Header>Share Object</Modal.Header>
|
||||
<Modal.Body>
|
||||
<div className="form-group">
|
||||
<ModalHeader>Share Object</ModalHeader>
|
||||
<ModalBody>
|
||||
<div className="input-group copy-text">
|
||||
<label>Shareable Link</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-group__field"
|
||||
ref={node => (this.copyTextInput = node)}
|
||||
readOnly="readOnly"
|
||||
value={window.location.protocol + "//" + shareObjectDetails.url}
|
||||
onClick={() => this.copyTextInput.select()}
|
||||
/>
|
||||
<i className="form-group__helper" />
|
||||
</div>
|
||||
<div
|
||||
className="form-group"
|
||||
className="input-group"
|
||||
style={{ display: web.LoggedIn() ? "block" : "none" }}
|
||||
>
|
||||
<label>Expires in (Max 7 days)</label>
|
||||
<div className="set-expire">
|
||||
<div className="set-expire__item">
|
||||
<div className="set-expire-item">
|
||||
<i
|
||||
id="increase-days"
|
||||
className="set-expire__handle zmdi zmdi-chevron-up"
|
||||
className="set-expire-increase"
|
||||
onClick={() => this.updateExpireValue("days", 1)}
|
||||
/>
|
||||
<div className="set-expire__title">Days</div>
|
||||
<div className="set-expire__value">
|
||||
<div className="set-expire-title">Days</div>
|
||||
<div className="set-expire-value">
|
||||
<input
|
||||
ref="expireDays"
|
||||
type="number"
|
||||
@@ -136,18 +122,18 @@ export class ShareObjectModal extends React.Component {
|
||||
</div>
|
||||
<i
|
||||
id="decrease-days"
|
||||
className="set-expire__handle zmdi zmdi-chevron-down"
|
||||
className="set-expire-decrease"
|
||||
onClick={() => this.updateExpireValue("days", -1)}
|
||||
/>
|
||||
</div>
|
||||
<div className="set-expire__item">
|
||||
<div className="set-expire-item">
|
||||
<i
|
||||
id="increase-hours"
|
||||
className="set-expire__handle zmdi zmdi-chevron-up"
|
||||
className="set-expire-increase"
|
||||
onClick={() => this.updateExpireValue("hours", 1)}
|
||||
/>
|
||||
<div className="set-expire__title">Hours</div>
|
||||
<div className="set-expire__value">
|
||||
<div className="set-expire-title">Hours</div>
|
||||
<div className="set-expire-value">
|
||||
<input
|
||||
ref="expireHours"
|
||||
type="number"
|
||||
@@ -158,19 +144,19 @@ export class ShareObjectModal extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
<i
|
||||
className="set-expire__handle zmdi zmdi-chevron-down"
|
||||
className="set-expire-decrease"
|
||||
id="decrease-hours"
|
||||
onClick={() => this.updateExpireValue("hours", -1)}
|
||||
/>
|
||||
</div>
|
||||
<div className="set-expire__item">
|
||||
<div className="set-expire-item">
|
||||
<i
|
||||
id="increase-minutes"
|
||||
className="set-expire__handle zmdi zmdi-chevron-up"
|
||||
className="set-expire-increase"
|
||||
onClick={() => this.updateExpireValue("minutes", 1)}
|
||||
/>
|
||||
<div className="set-expire__title">Minutes</div>
|
||||
<div className="set-expire__value">
|
||||
<div className="set-expire-title">Minutes</div>
|
||||
<div className="set-expire-value">
|
||||
<input
|
||||
ref="expireMins"
|
||||
type="number"
|
||||
@@ -182,21 +168,21 @@ export class ShareObjectModal extends React.Component {
|
||||
</div>
|
||||
<i
|
||||
id="decrease-minutes"
|
||||
className="set-expire__handle zmdi zmdi-chevron-down"
|
||||
className="set-expire-decrease"
|
||||
onClick={() => this.updateExpireValue("minutes", -1)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal.Body>
|
||||
</ModalBody>
|
||||
<div className="modal-footer">
|
||||
<CopyToClipboard
|
||||
text={window.location.protocol + "//" + shareObjectDetails.url}
|
||||
onCopy={this.onUrlCopied.bind(this)}
|
||||
>
|
||||
<button className="btn btn--link">Copy Link</button>
|
||||
<button className="btn btn-success">Copy Link</button>
|
||||
</CopyToClipboard>
|
||||
<button className="btn btn--link" onClick={hideShareObject}>
|
||||
<button className="btn btn-link" onClick={hideShareObject}>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
@@ -207,6 +193,7 @@ export class ShareObjectModal extends React.Component {
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
object: ownProps.object,
|
||||
shareObjectDetails: state.objects.shareObject
|
||||
}
|
||||
}
|
||||
@@ -217,12 +204,7 @@ const mapDispatchToProps = dispatch => {
|
||||
dispatch(objectsActions.shareObject(object, days, hours, minutes)),
|
||||
hideShareObject: () => dispatch(objectsActions.hideShareObject()),
|
||||
showCopyAlert: message =>
|
||||
dispatch(
|
||||
alertActions.set({
|
||||
type: "success",
|
||||
message: message
|
||||
})
|
||||
)
|
||||
dispatch(alertActions.set({ type: "success", message: message }))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Minio Cloud Storage (C) 2018 Minio, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react"
|
||||
import { connect } from "react-redux"
|
||||
import * as actions from "./actions"
|
||||
import { getCheckedList } from "./selectors"
|
||||
import DeleteObjectConfirmModal from "./DeleteObjectConfirmModal"
|
||||
import BrowserDropdown from "../browser/BrowserDropdown"
|
||||
import SidebarToggle from "../browser/SidebarToggle"
|
||||
import { minioBrowserPrefix } from "../constants"
|
||||
import ShareObjectModal from "./ShareObjectModal"
|
||||
import web from "../web"
|
||||
import * as objectsActions from "./actions"
|
||||
import {
|
||||
SHARE_OBJECT_EXPIRY_DAYS,
|
||||
SHARE_OBJECT_EXPIRY_HOURS,
|
||||
SHARE_OBJECT_EXPIRY_MINUTES
|
||||
} from "../constants"
|
||||
|
||||
export class Toolbar extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
showDeleteConfirmation: false
|
||||
}
|
||||
}
|
||||
deleteChecked() {
|
||||
const { deleteChecked } = this.props
|
||||
deleteChecked()
|
||||
this.hideDeleteConfirmModal()
|
||||
}
|
||||
hideDeleteConfirmModal() {
|
||||
this.setState({
|
||||
showDeleteConfirmation: false
|
||||
})
|
||||
}
|
||||
shareObject(e) {
|
||||
e.preventDefault()
|
||||
const { checkedObjects, shareObject } = this.props
|
||||
if (checkedObjects.length != 1) {
|
||||
return
|
||||
}
|
||||
const object = checkedObjects[0]
|
||||
shareObject(
|
||||
object,
|
||||
SHARE_OBJECT_EXPIRY_DAYS,
|
||||
SHARE_OBJECT_EXPIRY_HOURS,
|
||||
SHARE_OBJECT_EXPIRY_MINUTES
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
checkedObjectsCount,
|
||||
downloadChecked,
|
||||
object,
|
||||
showShareObjectModal
|
||||
} = this.props
|
||||
const loggedIn = web.LoggedIn()
|
||||
|
||||
return (
|
||||
<div className="toolbar">
|
||||
<SidebarToggle />
|
||||
<button
|
||||
className="toolbar__item zmdi zmdi-delete"
|
||||
onClick={() =>
|
||||
this.setState({
|
||||
showDeleteConfirmation: true
|
||||
})
|
||||
}
|
||||
disabled={!checkedObjectsCount}
|
||||
/>
|
||||
{loggedIn ? (
|
||||
<button
|
||||
className="toolbar__item zmdi zmdi-share"
|
||||
onClick={this.shareObject.bind(this)}
|
||||
disabled={checkedObjectsCount != 1}
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<button
|
||||
className="toolbar__item zmdi zmdi-download"
|
||||
onClick={downloadChecked}
|
||||
disabled={!checkedObjectsCount}
|
||||
/>
|
||||
{showShareObjectModal && <ShareObjectModal object={object} />}
|
||||
<div className="toolbar__end">
|
||||
{loggedIn ? (
|
||||
<BrowserDropdown />
|
||||
) : (
|
||||
<a
|
||||
className="toolbar__item toolbar__item--alt btn btn--danger"
|
||||
href={minioBrowserPrefix + "/login"}
|
||||
>
|
||||
Login
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
{this.state.showDeleteConfirmation && (
|
||||
<DeleteObjectConfirmModal
|
||||
deleteObject={this.deleteChecked.bind(this)}
|
||||
hideDeleteConfirmModal={this.hideDeleteConfirmModal.bind(this)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
checkedObjects: getCheckedList(state),
|
||||
checkedObjectsCount: getCheckedList(state).length,
|
||||
showShareObjectModal: state.objects.shareObject.show
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
downloadChecked: () => dispatch(actions.downloadCheckedObjects()),
|
||||
clearChecked: () => dispatch(actions.resetCheckedList()),
|
||||
deleteChecked: () => dispatch(actions.deleteCheckedObjects()),
|
||||
toggleSidebar: () => dispatch(actionsCommon.toggleSidebar()),
|
||||
shareObject: (object, days, hours, minutes) =>
|
||||
dispatch(objectsActions.shareObject(object, days, hours, minutes))
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Toolbar)
|
||||
95
browser/app/js/objects/__tests__/ObjectActions.test.js
Normal file
95
browser/app/js/objects/__tests__/ObjectActions.test.js
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Minio Cloud Storage (C) 2018 Minio, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react"
|
||||
import { shallow } from "enzyme"
|
||||
import { ObjectActions } from "../ObjectActions"
|
||||
|
||||
describe("ObjectActions", () => {
|
||||
it("should render without crashing", () => {
|
||||
shallow(<ObjectActions object={{ name: "obj1" }} currentPrefix={"pre1/"} />)
|
||||
})
|
||||
|
||||
it("should show DeleteObjectConfirmModal when delete action is clicked", () => {
|
||||
const wrapper = shallow(
|
||||
<ObjectActions object={{ name: "obj1" }} currentPrefix={"pre1/"} />
|
||||
)
|
||||
wrapper
|
||||
.find("a")
|
||||
.last()
|
||||
.simulate("click", { preventDefault: jest.fn() })
|
||||
expect(wrapper.state("showDeleteConfirmation")).toBeTruthy()
|
||||
expect(wrapper.find("DeleteObjectConfirmModal").length).toBe(1)
|
||||
})
|
||||
|
||||
it("should hide DeleteObjectConfirmModal when Cancel button is clicked", () => {
|
||||
const wrapper = shallow(
|
||||
<ObjectActions object={{ name: "obj1" }} currentPrefix={"pre1/"} />
|
||||
)
|
||||
wrapper
|
||||
.find("a")
|
||||
.last()
|
||||
.simulate("click", { preventDefault: jest.fn() })
|
||||
wrapper.find("DeleteObjectConfirmModal").prop("hideDeleteConfirmModal")()
|
||||
wrapper.update()
|
||||
expect(wrapper.state("showDeleteConfirmation")).toBeFalsy()
|
||||
expect(wrapper.find("DeleteObjectConfirmModal").length).toBe(0)
|
||||
})
|
||||
|
||||
it("should call deleteObject with object name", () => {
|
||||
const deleteObject = jest.fn()
|
||||
const wrapper = shallow(
|
||||
<ObjectActions
|
||||
object={{ name: "obj1" }}
|
||||
currentPrefix={"pre1/"}
|
||||
deleteObject={deleteObject}
|
||||
/>
|
||||
)
|
||||
wrapper
|
||||
.find("a")
|
||||
.last()
|
||||
.simulate("click", { preventDefault: jest.fn() })
|
||||
wrapper.find("DeleteObjectConfirmModal").prop("deleteObject")()
|
||||
expect(deleteObject).toHaveBeenCalledWith("obj1")
|
||||
})
|
||||
|
||||
it("should call shareObject with object and expiry", () => {
|
||||
const shareObject = jest.fn()
|
||||
const wrapper = shallow(
|
||||
<ObjectActions
|
||||
object={{ name: "obj1" }}
|
||||
currentPrefix={"pre1/"}
|
||||
shareObject={shareObject}
|
||||
/>
|
||||
)
|
||||
wrapper
|
||||
.find("a")
|
||||
.first()
|
||||
.simulate("click", { preventDefault: jest.fn() })
|
||||
expect(shareObject).toHaveBeenCalledWith("obj1", 5, 0, 0)
|
||||
})
|
||||
|
||||
it("should render ShareObjectModal when an object is shared", () => {
|
||||
const wrapper = shallow(
|
||||
<ObjectActions
|
||||
object={{ name: "obj1" }}
|
||||
currentPrefix={"pre1/"}
|
||||
showShareObjectModal={true}
|
||||
/>
|
||||
)
|
||||
expect(wrapper.find("Connect(ShareObjectModal)").length).toBe(1)
|
||||
})
|
||||
})
|
||||
@@ -28,4 +28,22 @@ describe("ObjectContainer", () => {
|
||||
expect(wrapper.find("Connect(ObjectItem)").length).toBe(1)
|
||||
expect(wrapper.find("Connect(ObjectItem)").prop("name")).toBe("test1.jpg")
|
||||
})
|
||||
|
||||
it("should pass actions to ObjectItem", () => {
|
||||
const wrapper = shallow(
|
||||
<ObjectContainer object={{ name: "test1.jpg" }} checkedObjectsCount={0} />
|
||||
)
|
||||
expect(wrapper.find("Connect(ObjectItem)").prop("actionButtons")).not.toBe(
|
||||
undefined
|
||||
)
|
||||
})
|
||||
|
||||
it("should pass empty actions to ObjectItem when checkedObjectCount is more than 0", () => {
|
||||
const wrapper = shallow(
|
||||
<ObjectContainer object={{ name: "test1.jpg" }} checkedObjectsCount={1} />
|
||||
)
|
||||
expect(wrapper.find("Connect(ObjectItem)").prop("actionButtons")).toBe(
|
||||
undefined
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -25,17 +25,13 @@ describe("ObjectItem", () => {
|
||||
|
||||
it("should render with content type", () => {
|
||||
const wrapper = shallow(<ObjectItem name={"test.jpg"} contentType={""} />)
|
||||
expect(
|
||||
wrapper.find(".objects__column--select").prop("data-object-type")
|
||||
).toBe("image")
|
||||
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()
|
||||
})
|
||||
wrapper.find("a").simulate("click", { preventDefault: jest.fn() })
|
||||
expect(onClick).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
|
||||
@@ -16,38 +16,42 @@
|
||||
|
||||
import React from "react"
|
||||
import { shallow } from "enzyme"
|
||||
import { Toolbar } from "../Toolbar"
|
||||
import { ObjectsBulkActions } from "../ObjectsBulkActions"
|
||||
|
||||
jest.mock("../../web", () => ({
|
||||
LoggedIn: jest
|
||||
.fn(() => true)
|
||||
.mockReturnValueOnce(true)
|
||||
.mockReturnValueOnce(false)
|
||||
}))
|
||||
|
||||
describe("Toolbar", () => {
|
||||
describe("ObjectsBulkActions", () => {
|
||||
it("should render without crashing", () => {
|
||||
shallow(<Toolbar checkedObjectsCount={0} />)
|
||||
shallow(<ObjectsBulkActions checkedObjectsCount={0} />)
|
||||
})
|
||||
|
||||
it("should render Login button when the user has not LoggedIn", () => {
|
||||
const wrapper = shallow(<Toolbar checkedObjectsCount={0} />)
|
||||
expect(wrapper.find("a").text()).toBe("Login")
|
||||
it("should show actions when checkObjectsCount is more than 0", () => {
|
||||
const wrapper = shallow(<ObjectsBulkActions checkedObjectsCount={1} />)
|
||||
expect(wrapper.hasClass("list-actions-toggled")).toBeTruthy()
|
||||
})
|
||||
|
||||
it("should render StorageInfo and BrowserDropdown when the user has LoggedIn", () => {
|
||||
const wrapper = shallow(<Toolbar checkedObjectsCount={0} />)
|
||||
expect(wrapper.find("Connect(BrowserDropdown)").length).toBe(1)
|
||||
it("should call downloadChecked when download button is clicked", () => {
|
||||
const downloadChecked = jest.fn()
|
||||
const wrapper = shallow(
|
||||
<ObjectsBulkActions
|
||||
checkedObjectsCount={1}
|
||||
downloadChecked={downloadChecked}
|
||||
/>
|
||||
)
|
||||
wrapper.find("#download-checked").simulate("click")
|
||||
expect(downloadChecked).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should enable delete action when checkObjectsCount is more than 0", () => {
|
||||
const wrapper = shallow(<Toolbar checkedObjectsCount={1} />)
|
||||
expect(wrapper.find(".zmdi-delete").prop("disabled")).toBeFalsy()
|
||||
it("should call clearChecked when close button is clicked", () => {
|
||||
const clearChecked = jest.fn()
|
||||
const wrapper = shallow(
|
||||
<ObjectsBulkActions checkedObjectsCount={1} clearChecked={clearChecked} />
|
||||
)
|
||||
wrapper.find("#close-bulk-actions").simulate("click")
|
||||
expect(clearChecked).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("shoud show DeleteObjectConfirmModal when delete button is clicked", () => {
|
||||
const wrapper = shallow(<Toolbar checkedObjectsCount={1} />)
|
||||
wrapper.find("button.zmdi-delete").simulate("click")
|
||||
it("shoud show DeleteObjectConfirmModal when delete-checked button is clicked", () => {
|
||||
const wrapper = shallow(<ObjectsBulkActions checkedObjectsCount={1} />)
|
||||
wrapper.find("#delete-checked").simulate("click")
|
||||
wrapper.update()
|
||||
expect(wrapper.find("DeleteObjectConfirmModal").length).toBe(1)
|
||||
})
|
||||
@@ -55,22 +59,16 @@ describe("Toolbar", () => {
|
||||
it("shoud call deleteChecked when Delete is clicked on confirmation modal", () => {
|
||||
const deleteChecked = jest.fn()
|
||||
const wrapper = shallow(
|
||||
<Toolbar checkedObjectsCount={1} deleteChecked={deleteChecked} />
|
||||
<ObjectsBulkActions
|
||||
checkedObjectsCount={1}
|
||||
deleteChecked={deleteChecked}
|
||||
/>
|
||||
)
|
||||
wrapper.find("button.zmdi-delete").simulate("click")
|
||||
wrapper.find("#delete-checked").simulate("click")
|
||||
wrapper.update()
|
||||
wrapper.find("DeleteObjectConfirmModal").prop("deleteObject")()
|
||||
expect(deleteChecked).toHaveBeenCalled()
|
||||
wrapper.update()
|
||||
expect(wrapper.find("DeleteObjectConfirmModal").length).toBe(0)
|
||||
})
|
||||
|
||||
it("should call downloadChecked when download button is clicked", () => {
|
||||
const downloadChecked = jest.fn()
|
||||
const wrapper = shallow(
|
||||
<Toolbar checkedObjectsCount={1} downloadChecked={downloadChecked} />
|
||||
)
|
||||
wrapper.find("button.zmdi-download").simulate("click")
|
||||
expect(downloadChecked).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -28,13 +28,13 @@ describe("ObjectsHeader", () => {
|
||||
const sortObjects = jest.fn()
|
||||
const wrapper = shallow(<ObjectsHeader sortObjects={sortObjects} />)
|
||||
expect(
|
||||
wrapper.find("#sort-by-name i").hasClass("zmdi-sort-asc")
|
||||
wrapper.find("#sort-by-name i").hasClass("fa-sort-alpha-asc")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
wrapper.find("#sort-by-size i").hasClass("zmdi-sort-amount-asc")
|
||||
wrapper.find("#sort-by-size i").hasClass("fa-sort-amount-asc")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
wrapper.find("#sort-by-last-modified i").hasClass("zmdi-sort-amount-asc")
|
||||
wrapper.find("#sort-by-last-modified i").hasClass("fa-sort-numeric-asc")
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
@@ -44,7 +44,7 @@ describe("ObjectsHeader", () => {
|
||||
<ObjectsHeader sortObjects={sortObjects} sortNameOrder={true} />
|
||||
)
|
||||
expect(
|
||||
wrapper.find("#sort-by-name i").hasClass("zmdi-sort-desc")
|
||||
wrapper.find("#sort-by-name i").hasClass("fa-sort-alpha-desc")
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
@@ -54,7 +54,7 @@ describe("ObjectsHeader", () => {
|
||||
<ObjectsHeader sortObjects={sortObjects} sortSizeOrder={true} />
|
||||
)
|
||||
expect(
|
||||
wrapper.find("#sort-by-size i").hasClass("zmdi-sort-amount-desc")
|
||||
wrapper.find("#sort-by-size i").hasClass("fa-sort-amount-desc")
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
@@ -64,7 +64,7 @@ describe("ObjectsHeader", () => {
|
||||
<ObjectsHeader sortObjects={sortObjects} sortLastModifiedOrder={true} />
|
||||
)
|
||||
expect(
|
||||
wrapper.find("#sort-by-last-modified i").hasClass("zmdi-sort-amount-desc")
|
||||
wrapper.find("#sort-by-last-modified i").hasClass("fa-sort-numeric-desc")
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
|
||||
@@ -32,12 +32,8 @@ describe("ObjectsList", () => {
|
||||
)
|
||||
expect(wrapper.find("ObjectsList").length).toBe(1)
|
||||
expect(wrapper.find("ObjectsList").prop("objects")).toEqual([
|
||||
{
|
||||
name: "test1.jpg"
|
||||
},
|
||||
{
|
||||
name: "test2.jpg"
|
||||
}
|
||||
{ name: "test1.jpg" },
|
||||
{ name: "test2.jpg" }
|
||||
])
|
||||
})
|
||||
|
||||
@@ -45,9 +41,6 @@ describe("ObjectsList", () => {
|
||||
const wrapper = shallow(
|
||||
<ObjectsListContainer currentBucket="test1" isTruncated={true} />
|
||||
)
|
||||
expect(wrapper.find(".text-center").prop("style")).toHaveProperty(
|
||||
"display",
|
||||
"block"
|
||||
)
|
||||
expect(wrapper.find(".text-center").prop("style")).toHaveProperty("display", "block")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -25,7 +25,7 @@ describe("Path", () => {
|
||||
|
||||
it("should render only bucket if there is no prefix", () => {
|
||||
const wrapper = shallow(<Path currentBucket={"test1"} currentPrefix={""} />)
|
||||
expect(wrapper.find("a").length).toBe(1)
|
||||
expect(wrapper.find("span").length).toBe(1)
|
||||
expect(wrapper.text()).toBe("test1")
|
||||
})
|
||||
|
||||
@@ -33,22 +33,22 @@ describe("Path", () => {
|
||||
const wrapper = shallow(
|
||||
<Path currentBucket={"test1"} currentPrefix={"a/b/"} />
|
||||
)
|
||||
expect(wrapper.find("a").length).toBe(3)
|
||||
expect(wrapper.find("span").length).toBe(3)
|
||||
expect(
|
||||
wrapper
|
||||
.find("a")
|
||||
.find("span")
|
||||
.at(0)
|
||||
.text()
|
||||
).toBe("test1")
|
||||
expect(
|
||||
wrapper
|
||||
.find("a")
|
||||
.find("span")
|
||||
.at(1)
|
||||
.text()
|
||||
).toBe("a")
|
||||
expect(
|
||||
wrapper
|
||||
.find("a")
|
||||
.find("span")
|
||||
.at(2)
|
||||
.text()
|
||||
).toBe("b")
|
||||
@@ -66,9 +66,7 @@ describe("Path", () => {
|
||||
wrapper
|
||||
.find("a")
|
||||
.at(2)
|
||||
.simulate("click", {
|
||||
preventDefault: jest.fn()
|
||||
})
|
||||
.simulate("click", { preventDefault: jest.fn() })
|
||||
expect(selectPrefix).toHaveBeenCalledWith("a/b/")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -88,14 +88,8 @@ describe("ShareObjectModal", () => {
|
||||
|
||||
describe("Update expiry values", () => {
|
||||
const props = {
|
||||
object: {
|
||||
name: "obj1"
|
||||
},
|
||||
shareObjectDetails: {
|
||||
show: true,
|
||||
object: "obj1",
|
||||
url: "test"
|
||||
}
|
||||
object: { name: "obj1" },
|
||||
shareObjectDetails: { show: true, object: "obj1", url: "test" }
|
||||
}
|
||||
it("should have default expiry values", () => {
|
||||
const wrapper = shallow(<ShareObjectModal {...props} />)
|
||||
|
||||
@@ -24,14 +24,7 @@ jest.mock("../../web", () => ({
|
||||
LoggedIn: jest.fn(() => true).mockReturnValueOnce(false),
|
||||
ListObjects: jest.fn(() => {
|
||||
return Promise.resolve({
|
||||
objects: [
|
||||
{
|
||||
name: "test1"
|
||||
},
|
||||
{
|
||||
name: "test2"
|
||||
}
|
||||
],
|
||||
objects: [{ name: "test1" }, { name: "test2" }],
|
||||
istruncated: false,
|
||||
nextmarker: "test2",
|
||||
writable: false
|
||||
@@ -39,38 +32,26 @@ jest.mock("../../web", () => ({
|
||||
}),
|
||||
RemoveObject: jest.fn(({ bucketName, objects }) => {
|
||||
if (!bucketName) {
|
||||
return Promise.reject({
|
||||
message: "Invalid bucket"
|
||||
})
|
||||
return Promise.reject({ message: "Invalid bucket" })
|
||||
}
|
||||
return Promise.resolve({})
|
||||
}),
|
||||
PresignedGet: jest.fn(({ bucket, object }) => {
|
||||
if (!bucket) {
|
||||
return Promise.reject({
|
||||
message: "Invalid bucket"
|
||||
})
|
||||
return Promise.reject({ message: "Invalid bucket" })
|
||||
}
|
||||
return Promise.resolve({
|
||||
url: "https://test.com/bk1/pre1/b.txt"
|
||||
})
|
||||
return Promise.resolve({ url: "https://test.com/bk1/pre1/b.txt" })
|
||||
}),
|
||||
CreateURLToken: jest
|
||||
.fn()
|
||||
.mockImplementationOnce(() => {
|
||||
return Promise.resolve({
|
||||
token: "test"
|
||||
})
|
||||
return Promise.resolve({ token: "test" })
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
return Promise.reject({
|
||||
message: "Error in creating token"
|
||||
})
|
||||
return Promise.reject({ message: "Error in creating token" })
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
return Promise.resolve({
|
||||
token: "test"
|
||||
})
|
||||
return Promise.resolve({ token: "test" })
|
||||
})
|
||||
}))
|
||||
|
||||
@@ -83,28 +64,14 @@ describe("Objects actions", () => {
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/SET_LIST",
|
||||
objects: [
|
||||
{
|
||||
name: "test1"
|
||||
},
|
||||
{
|
||||
name: "test2"
|
||||
}
|
||||
],
|
||||
objects: [{ name: "test1" }, { name: "test2" }],
|
||||
isTruncated: false,
|
||||
marker: "test2"
|
||||
}
|
||||
]
|
||||
store.dispatch(
|
||||
actionsObjects.setList(
|
||||
[
|
||||
{
|
||||
name: "test1"
|
||||
},
|
||||
{
|
||||
name: "test2"
|
||||
}
|
||||
],
|
||||
[{ name: "test1" }, { name: "test2" }],
|
||||
"test2",
|
||||
false
|
||||
)
|
||||
@@ -141,24 +108,13 @@ describe("Objects actions", () => {
|
||||
|
||||
it("creates objects/SET_LIST after fetching the objects", () => {
|
||||
const store = mockStore({
|
||||
buckets: {
|
||||
currentBucket: "bk1"
|
||||
},
|
||||
objects: {
|
||||
currentPrefix: ""
|
||||
}
|
||||
buckets: { currentBucket: "bk1" },
|
||||
objects: { currentPrefix: "" }
|
||||
})
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/SET_LIST",
|
||||
objects: [
|
||||
{
|
||||
name: "test1"
|
||||
},
|
||||
{
|
||||
name: "test2"
|
||||
}
|
||||
],
|
||||
objects: [{ name: "test1" }, { name: "test2" }],
|
||||
marker: "test2",
|
||||
isTruncated: false
|
||||
},
|
||||
@@ -183,24 +139,13 @@ describe("Objects actions", () => {
|
||||
|
||||
it("creates objects/APPEND_LIST after fetching more objects", () => {
|
||||
const store = mockStore({
|
||||
buckets: {
|
||||
currentBucket: "bk1"
|
||||
},
|
||||
objects: {
|
||||
currentPrefix: ""
|
||||
}
|
||||
buckets: { currentBucket: "bk1" },
|
||||
objects: { currentPrefix: "" }
|
||||
})
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/APPEND_LIST",
|
||||
objects: [
|
||||
{
|
||||
name: "test1"
|
||||
},
|
||||
{
|
||||
name: "test2"
|
||||
}
|
||||
],
|
||||
objects: [{ name: "test1" }, { name: "test2" }],
|
||||
marker: "test2",
|
||||
isTruncated: false
|
||||
},
|
||||
@@ -248,21 +193,12 @@ describe("Objects actions", () => {
|
||||
|
||||
it("should update browser url and creates objects/SET_CURRENT_PREFIX and objects/CHECKED_LIST_RESET actions when selectPrefix is called", () => {
|
||||
const store = mockStore({
|
||||
buckets: {
|
||||
currentBucket: "test"
|
||||
},
|
||||
objects: {
|
||||
currentPrefix: ""
|
||||
}
|
||||
buckets: { currentBucket: "test" },
|
||||
objects: { currentPrefix: "" }
|
||||
})
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/SET_CURRENT_PREFIX",
|
||||
prefix: "abc/"
|
||||
},
|
||||
{
|
||||
type: "objects/CHECKED_LIST_RESET"
|
||||
}
|
||||
{ type: "objects/SET_CURRENT_PREFIX", prefix: "abc/" },
|
||||
{ type: "objects/CHECKED_LIST_RESET" }
|
||||
]
|
||||
store.dispatch(actionsObjects.selectPrefix("abc/"))
|
||||
const actions = store.getActions()
|
||||
@@ -273,10 +209,7 @@ describe("Objects actions", () => {
|
||||
it("create objects/SET_PREFIX_WRITABLE action", () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/SET_PREFIX_WRITABLE",
|
||||
prefixWritable: true
|
||||
}
|
||||
{ type: "objects/SET_PREFIX_WRITABLE", prefixWritable: true }
|
||||
]
|
||||
store.dispatch(actionsObjects.setPrefixWritable(true))
|
||||
const actions = store.getActions()
|
||||
@@ -285,12 +218,7 @@ describe("Objects actions", () => {
|
||||
|
||||
it("creates objects/REMOVE action", () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/REMOVE",
|
||||
object: "obj1"
|
||||
}
|
||||
]
|
||||
const expectedActions = [{ type: "objects/REMOVE", object: "obj1" }]
|
||||
store.dispatch(actionsObjects.removeObject("obj1"))
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
@@ -298,19 +226,10 @@ describe("Objects actions", () => {
|
||||
|
||||
it("creates objects/REMOVE action when object is deleted", () => {
|
||||
const store = mockStore({
|
||||
buckets: {
|
||||
currentBucket: "test"
|
||||
},
|
||||
objects: {
|
||||
currentPrefix: "pre1/"
|
||||
}
|
||||
buckets: { currentBucket: "test" },
|
||||
objects: { currentPrefix: "pre1/" }
|
||||
})
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/REMOVE",
|
||||
object: "obj1"
|
||||
}
|
||||
]
|
||||
const expectedActions = [{ type: "objects/REMOVE", object: "obj1" }]
|
||||
store.dispatch(actionsObjects.deleteObject("obj1")).then(() => {
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
@@ -319,21 +238,13 @@ describe("Objects actions", () => {
|
||||
|
||||
it("creates alert/SET action when invalid bucket is provided", () => {
|
||||
const store = mockStore({
|
||||
buckets: {
|
||||
currentBucket: ""
|
||||
},
|
||||
objects: {
|
||||
currentPrefix: "pre1/"
|
||||
}
|
||||
buckets: { currentBucket: "" },
|
||||
objects: { currentPrefix: "pre1/" }
|
||||
})
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "alert/SET",
|
||||
alert: {
|
||||
type: "danger",
|
||||
message: "Invalid bucket",
|
||||
id: 0
|
||||
}
|
||||
alert: { type: "danger", message: "Invalid bucket", id: 0 }
|
||||
}
|
||||
]
|
||||
return store.dispatch(actionsObjects.deleteObject("obj1")).then(() => {
|
||||
@@ -374,12 +285,8 @@ describe("Objects actions", () => {
|
||||
|
||||
it("creates objects/SET_SHARE_OBJECT when object is shared", () => {
|
||||
const store = mockStore({
|
||||
buckets: {
|
||||
currentBucket: "bk1"
|
||||
},
|
||||
objects: {
|
||||
currentPrefix: "pre1/"
|
||||
}
|
||||
buckets: { currentBucket: "bk1" },
|
||||
objects: { currentPrefix: "pre1/" }
|
||||
})
|
||||
const expectedActions = [
|
||||
{
|
||||
@@ -407,12 +314,8 @@ describe("Objects actions", () => {
|
||||
|
||||
it("creates alert/SET when shareObject is failed", () => {
|
||||
const store = mockStore({
|
||||
buckets: {
|
||||
currentBucket: ""
|
||||
},
|
||||
objects: {
|
||||
currentPrefix: "pre1/"
|
||||
}
|
||||
buckets: { currentBucket: "" },
|
||||
objects: { currentPrefix: "pre1/" }
|
||||
})
|
||||
const expectedActions = [
|
||||
{
|
||||
@@ -446,12 +349,8 @@ describe("Objects actions", () => {
|
||||
}
|
||||
})
|
||||
const store = mockStore({
|
||||
buckets: {
|
||||
currentBucket: "bk1"
|
||||
},
|
||||
objects: {
|
||||
currentPrefix: "pre1/"
|
||||
}
|
||||
buckets: { currentBucket: "bk1" },
|
||||
objects: { currentPrefix: "pre1/" }
|
||||
})
|
||||
store.dispatch(actionsObjects.downloadObject("obj1"))
|
||||
const url = `${
|
||||
@@ -473,12 +372,8 @@ describe("Objects actions", () => {
|
||||
}
|
||||
})
|
||||
const store = mockStore({
|
||||
buckets: {
|
||||
currentBucket: "bk1"
|
||||
},
|
||||
objects: {
|
||||
currentPrefix: "pre1/"
|
||||
}
|
||||
buckets: { currentBucket: "bk1" },
|
||||
objects: { currentPrefix: "pre1/" }
|
||||
})
|
||||
return store.dispatch(actionsObjects.downloadObject("obj1")).then(() => {
|
||||
const url = `${
|
||||
@@ -492,12 +387,8 @@ describe("Objects actions", () => {
|
||||
|
||||
it("create alert/SET action when CreateUrlToken fails", () => {
|
||||
const store = mockStore({
|
||||
buckets: {
|
||||
currentBucket: "bk1"
|
||||
},
|
||||
objects: {
|
||||
currentPrefix: "pre1/"
|
||||
}
|
||||
buckets: { currentBucket: "bk1" },
|
||||
objects: { currentPrefix: "pre1/" }
|
||||
})
|
||||
const expectedActions = [
|
||||
{
|
||||
@@ -564,13 +455,8 @@ describe("Objects actions", () => {
|
||||
window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass)
|
||||
|
||||
const store = mockStore({
|
||||
buckets: {
|
||||
currentBucket: "bk1"
|
||||
},
|
||||
objects: {
|
||||
currentPrefix: "pre1/",
|
||||
checkedList: ["obj1"]
|
||||
}
|
||||
buckets: { currentBucket: "bk1" },
|
||||
objects: { currentPrefix: "pre1/", checkedList: ["obj1"] }
|
||||
})
|
||||
return store.dispatch(actionsObjects.downloadCheckedObjects()).then(() => {
|
||||
const requestUrl = `${
|
||||
|
||||
@@ -40,25 +40,11 @@ describe("objects reducer", () => {
|
||||
it("should handle SET_LIST", () => {
|
||||
const newState = reducer(undefined, {
|
||||
type: actions.SET_LIST,
|
||||
objects: [
|
||||
{
|
||||
name: "obj1"
|
||||
},
|
||||
{
|
||||
name: "obj2"
|
||||
}
|
||||
],
|
||||
objects: [{ name: "obj1" }, { name: "obj2" }],
|
||||
marker: "obj2",
|
||||
isTruncated: false
|
||||
})
|
||||
expect(newState.list).toEqual([
|
||||
{
|
||||
name: "obj1"
|
||||
},
|
||||
{
|
||||
name: "obj2"
|
||||
}
|
||||
])
|
||||
expect(newState.list).toEqual([{ name: "obj1" }, { name: "obj2" }])
|
||||
expect(newState.marker).toBe("obj2")
|
||||
expect(newState.isTruncated).toBeFalsy()
|
||||
})
|
||||
@@ -66,44 +52,22 @@ describe("objects reducer", () => {
|
||||
it("should handle APPEND_LIST", () => {
|
||||
const newState = reducer(
|
||||
{
|
||||
list: [
|
||||
{
|
||||
name: "obj1"
|
||||
},
|
||||
{
|
||||
name: "obj2"
|
||||
}
|
||||
],
|
||||
list: [{ name: "obj1" }, { name: "obj2" }],
|
||||
marker: "obj2",
|
||||
isTruncated: true
|
||||
},
|
||||
{
|
||||
type: actions.APPEND_LIST,
|
||||
objects: [
|
||||
{
|
||||
name: "obj3"
|
||||
},
|
||||
{
|
||||
name: "obj4"
|
||||
}
|
||||
],
|
||||
objects: [{ name: "obj3" }, { name: "obj4" }],
|
||||
marker: "obj4",
|
||||
isTruncated: false
|
||||
}
|
||||
)
|
||||
expect(newState.list).toEqual([
|
||||
{
|
||||
name: "obj1"
|
||||
},
|
||||
{
|
||||
name: "obj2"
|
||||
},
|
||||
{
|
||||
name: "obj3"
|
||||
},
|
||||
{
|
||||
name: "obj4"
|
||||
}
|
||||
{ name: "obj1" },
|
||||
{ name: "obj2" },
|
||||
{ name: "obj3" },
|
||||
{ name: "obj4" }
|
||||
])
|
||||
expect(newState.marker).toBe("obj4")
|
||||
expect(newState.isTruncated).toBeFalsy()
|
||||
@@ -111,53 +75,24 @@ describe("objects reducer", () => {
|
||||
|
||||
it("should handle REMOVE", () => {
|
||||
const newState = reducer(
|
||||
{
|
||||
list: [
|
||||
{
|
||||
name: "obj1"
|
||||
},
|
||||
{
|
||||
name: "obj2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{ list: [{ name: "obj1" }, { name: "obj2" }] },
|
||||
{
|
||||
type: actions.REMOVE,
|
||||
object: "obj1"
|
||||
}
|
||||
)
|
||||
expect(newState.list).toEqual([
|
||||
{
|
||||
name: "obj2"
|
||||
}
|
||||
])
|
||||
expect(newState.list).toEqual([{ name: "obj2" }])
|
||||
})
|
||||
|
||||
it("should handle REMOVE with non-existent object", () => {
|
||||
const newState = reducer(
|
||||
{
|
||||
list: [
|
||||
{
|
||||
name: "obj1"
|
||||
},
|
||||
{
|
||||
name: "obj2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{ list: [{ name: "obj1" }, { name: "obj2" }] },
|
||||
{
|
||||
type: actions.REMOVE,
|
||||
object: "obj3"
|
||||
}
|
||||
)
|
||||
expect(newState.list).toEqual([
|
||||
{
|
||||
name: "obj1"
|
||||
},
|
||||
{
|
||||
name: "obj2"
|
||||
}
|
||||
])
|
||||
expect(newState.list).toEqual([{ name: "obj1" }, { name: "obj2" }])
|
||||
})
|
||||
|
||||
it("should handle SET_SORT_BY", () => {
|
||||
@@ -178,11 +113,7 @@ describe("objects reducer", () => {
|
||||
|
||||
it("should handle SET_CURRENT_PREFIX", () => {
|
||||
const newState = reducer(
|
||||
{
|
||||
currentPrefix: "test1/",
|
||||
marker: "abc",
|
||||
isTruncated: true
|
||||
},
|
||||
{ currentPrefix: "test1/", marker: "abc", isTruncated: true },
|
||||
{
|
||||
type: actions.SET_CURRENT_PREFIX,
|
||||
prefix: "test2/"
|
||||
@@ -225,9 +156,7 @@ describe("objects reducer", () => {
|
||||
|
||||
it("should handle SELECTED_LIST_REMOVE", () => {
|
||||
const newState = reducer(
|
||||
{
|
||||
checkedList: ["obj1", "obj2"]
|
||||
},
|
||||
{ checkedList: ["obj1", "obj2"] },
|
||||
{
|
||||
type: actions.CHECKED_LIST_REMOVE,
|
||||
object: "obj1"
|
||||
@@ -238,9 +167,7 @@ describe("objects reducer", () => {
|
||||
|
||||
it("should handle CHECKED_LIST_RESET", () => {
|
||||
const newState = reducer(
|
||||
{
|
||||
checkedList: ["obj1", "obj2"]
|
||||
},
|
||||
{ checkedList: ["obj1", "obj2"] },
|
||||
{
|
||||
type: actions.CHECKED_LIST_RESET
|
||||
}
|
||||
|
||||
@@ -60,40 +60,35 @@ export const fetchObjects = append => {
|
||||
} = getState()
|
||||
if (currentBucket) {
|
||||
return web
|
||||
.ListObjects({
|
||||
bucketName: currentBucket,
|
||||
prefix: currentPrefix,
|
||||
marker: append ? marker : ""
|
||||
})
|
||||
.then(res => {
|
||||
let objects = []
|
||||
if (res.objects) {
|
||||
objects = res.objects.map(object => {
|
||||
return {
|
||||
...object,
|
||||
name: object.name.replace(currentPrefix, "")
|
||||
}
|
||||
})
|
||||
}
|
||||
if (append) {
|
||||
dispatch(appendList(objects, res.nextmarker, res.istruncated))
|
||||
} else {
|
||||
dispatch(setList(objects, res.nextmarker, res.istruncated))
|
||||
dispatch(setSortBy(""))
|
||||
dispatch(setSortOrder(false))
|
||||
}
|
||||
dispatch(setPrefixWritable(res.writable))
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(
|
||||
alertActions.set({
|
||||
type: "danger",
|
||||
message: err.message
|
||||
})
|
||||
)
|
||||
history.push("/login")
|
||||
})
|
||||
}
|
||||
.ListObjects({
|
||||
bucketName: currentBucket,
|
||||
prefix: currentPrefix,
|
||||
marker: append ? marker : ""
|
||||
})
|
||||
.then(res => {
|
||||
let objects = []
|
||||
if (res.objects) {
|
||||
objects = res.objects.map(object => {
|
||||
return {
|
||||
...object,
|
||||
name: object.name.replace(currentPrefix, "")
|
||||
}
|
||||
})
|
||||
}
|
||||
if (append) {
|
||||
dispatch(appendList(objects, res.nextmarker, res.istruncated))
|
||||
} else {
|
||||
dispatch(setList(objects, res.nextmarker, res.istruncated))
|
||||
dispatch(setSortBy(""))
|
||||
dispatch(setSortOrder(false))
|
||||
}
|
||||
dispatch(setPrefixWritable(res.writable))
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(alertActions.set({ type: "danger", message: err.message }))
|
||||
history.push("/login")
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user