Refactor of components (#5499)

This commit is contained in:
Kanagaraj M
2018-02-10 08:04:14 +05:30
committed by Harshavardhana
parent 9ab6a8035f
commit feb726dd98
40 changed files with 1733 additions and 127 deletions

View File

@@ -18,6 +18,7 @@ import React from "react"
import classNames from "classnames"
import { connect } from "react-redux"
import SideBar from "./SideBar"
import MainContent from "./MainContent"
class Browser extends React.Component {
render() {
@@ -28,6 +29,7 @@ class Browser extends React.Component {
})}
>
<SideBar />
<MainContent />
</div>
)
}

View File

@@ -28,7 +28,7 @@ const mapStateToProps = (state, ownProps) => {
const mapDispatchToProps = dispatch => {
return {
selectBucket: bucket => dispatch(actionsBuckets.setCurrentBucket(bucket))
selectBucket: bucket => dispatch(actionsBuckets.selectBucket(bucket))
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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 Path from "./Path"
import StorageInfo from "./StorageInfo"
export const Header = () => (
<header className="fe-header">
<Path />
<StorageInfo />
</header>
)
export default Header

View File

@@ -0,0 +1,30 @@
/*
* 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 MobileHeader from "./MobileHeader"
import Header from "./Header"
import ObjectsSection from "./ObjectsSection"
export const MainContent = () => (
<div className="fe-body">
<MobileHeader />
<Header />
<ObjectsSection />
</div>
)
export default MainContent

View File

@@ -0,0 +1,60 @@
/*
* 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 classNames from "classnames"
import { connect } from "react-redux"
import logo from "../../img/logo.svg"
import * as actionsCommon from "../actions/common"
export const MobileHeader = ({ sidebarOpen, toggleSidebar }) => (
<header className="fe-header-mobile hidden-lg hidden-md">
<div
id="sidebar-toggle"
className={
"feh-trigger " +
classNames({
"feht-toggled": sidebarOpen
})
}
onClick={e => {
e.stopPropagation()
toggleSidebar()
}}
>
<div className="feht-lines">
<div className="top" />
<div className="center" />
<div className="bottom" />
</div>
</div>
<img className="mh-logo" src={logo} alt="" />
</header>
)
const mapStateToProps = state => {
return {
sidebarOpen: state.common.sidebarOpen
}
}
const mapDispatchToProps = dispatch => {
return {
toggleSidebar: () => dispatch(actionsCommon.toggleSidebar())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MobileHeader)

View File

@@ -0,0 +1,35 @@
/*
* 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 humanize from "humanize"
import Moment from "moment"
import ObjectItem from "./ObjectItem"
import * as actionsObjects from "../actions/objects"
export const ObjectContainer = ({ object }) => {
const actionButtons = []
const props = {
name: object.name,
contentType: object.contentType,
size: humanize.filesize(object.size),
lastModified: Moment(object.lastModified).format("lll"),
actionButtons: []
}
return <ObjectItem {...props} />
}
export default ObjectContainer

View File

@@ -0,0 +1,58 @@
/*
* 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 humanize from "humanize"
import Moment from "moment"
import { getDataType } from "../mime"
export const ObjectItem = ({
name,
contentType,
size,
lastModified,
actionButtons,
onClick
}) => {
return (
<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} checked={false} />
<i className="fis-icon" />
<i className="fis-helper" />
</div>
</div>
<div className="fesl-item fesl-item-name">
<a
href="#"
onClick={e => {
e.preventDefault()
onClick()
}}
>
{name}
</a>
</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>
)
}
export default ObjectItem

View File

@@ -0,0 +1,99 @@
/*
* 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 classNames from "classnames"
import { connect } from "react-redux"
import * as actionsObjects from "../actions/objects"
export const ObjectsHeader = ({
sortNameOrder,
sortSizeOrder,
sortLastModifiedOrder,
sortObjects
}) => (
<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>
)
const mapStateToProps = state => {
return {
sortNameOrder: state.objects.sortBy == "name" && state.objects.sortOrder,
sortSizeOrder: state.objects.sortBy == "size" && state.objects.sortOrder,
sortLastModifiedOrder:
state.objects.sortBy == "last-modified" && state.objects.sortOrder
}
}
const mapDispatchToProps = dispatch => {
return {
sortObjects: sortBy => dispatch(actionsObjects.sortObjects(sortBy))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ObjectsHeader)

View File

@@ -1,5 +1,5 @@
/*
* Minio Cloud Storage (C) 2016 Minio, Inc.
* Minio Cloud Storage (C) 2016, 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.
@@ -14,83 +14,19 @@
* limitations under the License.
*/
import React from 'react'
import Moment from 'moment'
import humanize from 'humanize'
import connect from 'react-redux/lib/components/connect'
import Dropdown from 'react-bootstrap/lib/Dropdown'
import React from "react"
import ObjectContainer from "./ObjectContainer"
import PrefixContainer from "./PrefixContainer"
let ObjectsList = ({objects, currentPath, selectPrefix, dataType, showDeleteConfirmation, shareObject, loadPath, checkObject, checkedObjectsArray}) => {
const list = objects.map((object, i) => {
let size = object.name.endsWith('/') ? '-' : humanize.filesize(object.size)
let lastModified = object.name.endsWith('/') ? '-' : Moment(object.lastModified).format('lll')
let loadingClass = loadPath === `${currentPath}${object.name}` ? 'fesl-loading' : ''
let actionButtons = ''
let deleteButton = ''
if (web.LoggedIn())
deleteButton = <a href="" className="fiad-action" onClick={ (e) => showDeleteConfirmation(e, `${currentPath}${object.name}`) }><i className="fa fa-trash"></i></a>
if (!checkedObjectsArray.length > 0) {
if (!object.name.endsWith('/')) {
actionButtons = <Dropdown id={ "fia-dropdown-" + object.name.replace('.', '-') }>
<Dropdown.Toggle noCaret className="fia-toggle"></Dropdown.Toggle>
<Dropdown.Menu>
<a href="" className="fiad-action" onClick={ (e) => shareObject(e, `${currentPath}${object.name}`) }><i className="fa fa-copy"></i></a>
{ deleteButton }
</Dropdown.Menu>
</Dropdown>
}
export const ObjectsList = ({ objects }) => {
const list = objects.map(object => {
if (object.name.endsWith("/")) {
return <PrefixContainer object={object} key={object.name} />
} else {
return <ObjectContainer object={object} key={object.name} />
}
let activeClass = ''
let isChecked = ''
if (checkedObjectsArray.indexOf(object.name) > -1) {
activeClass = ' fesl-row-selected'
isChecked = true
}
return (
<div key={ i } className={ "fesl-row " + loadingClass + activeClass } data-type={ dataType(object.name, object.contentType) }>
<div className="fesl-item fesl-item-icon">
<div className="fi-select">
<input type="checkbox"
name={ object.name }
checked={ isChecked }
onChange={ (e) => checkObject(e, object.name) } />
<i className="fis-icon"></i>
<i className="fis-helper"></i>
</div>
</div>
<div className="fesl-item fesl-item-name">
<a href="" onClick={ (e) => selectPrefix(e, `${currentPath}${object.name}`) }>
{ object.name }
</a>
</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>
)
})
return (
<div>
{ list }
</div>
)
return <div>{list}</div>
}
// Subscribe it to state changes.
export default connect(state => {
return {
objects: state.objects,
currentPath: state.currentPath,
loadPath: state.loadPath
}
})(ObjectsList)
export default ObjectsList

View File

@@ -0,0 +1,75 @@
/*
* 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 classNames from "classnames"
import { connect } from "react-redux"
import InfiniteScroll from "react-infinite-scroller"
import * as actionsObjects from "../actions/objects"
import ObjectsList from "./ObjectsList"
export class ObjectsListContainer extends React.Component {
componentWillReceiveProps(nextProps) {
const { currentBucket, currentPrefix, loadObjects } = this.props
if (
currentBucket != nextProps.currentBucket ||
currentPrefix != nextProps.currentPrefix
) {
loadObjects()
}
}
render() {
const { objects, isTruncated, currentBucket, loadObjects } = this.props
return (
<div className="feb-container">
<InfiniteScroll
pageStart={0}
loadMore={() => loadObjects(true)}
hasMore={isTruncated}
useWindow={true}
initialLoad={false}
>
<ObjectsList objects={objects} />
</InfiniteScroll>
<div
className="text-center"
style={{ display: isTruncated && currentBucket ? "block" : "none" }}
>
<span>Loading...</span>
</div>
</div>
)
}
}
const mapStateToProps = state => {
return {
currentBucket: state.buckets.currentBucket,
currentPrefix: state.objects.currentPrefix,
objects: state.objects.list,
isTruncated: state.objects.isTruncated
}
}
const mapDispatchToProps = dispatch => {
return {
loadObjects: append => dispatch(actionsObjects.fetchObjects(append))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(
ObjectsListContainer
)

View File

@@ -0,0 +1,28 @@
/*
* 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 ObjectsHeader from "./ObjectsHeader"
import ObjectsListContainer from "./ObjectsListContainer"
export const ObjectsSection = () => (
<div>
<ObjectsHeader />
<ObjectsListContainer />
</div>
)
export default ObjectsSection

View File

@@ -14,28 +14,57 @@
* limitations under the License.
*/
import React from 'react'
import connect from 'react-redux/lib/components/connect'
import React from "react"
import { connect } from "react-redux"
import { getCurrentBucket, getCurrentPrefix } from "../selectors/buckets"
import * as actionsObjects from "../actions/objects"
let Path = ({currentBucket, currentPath, selectPrefix}) => {
export const Path = ({ currentBucket, currentPrefix, selectPrefix }) => {
const onPrefixClick = (e, prefix) => {
e.preventDefault()
selectPrefix(prefix)
}
let dirPath = []
let path = ''
if (currentPath) {
path = currentPath.split('/').map((dir, i) => {
dirPath.push(dir)
let dirPath_ = dirPath.join('/') + '/'
return <span key={ i }><a href="" onClick={ (e) => selectPrefix(e, dirPath_) }>{ dir }</a></span>
let path = ""
if (currentPrefix) {
path = currentPrefix.split("/").map((dir, i) => {
if (dir) {
dirPath.push(dir)
let dirPath_ = dirPath.join("/") + "/"
return (
<span key={i}>
<a href="" onClick={e => onPrefixClick(e, dirPath_)}>
{dir}
</a>
</span>
)
}
})
}
return (
<h2><span className="main"><a onClick={ (e) => selectPrefix(e, '') } href="">{ currentBucket }</a></span>{ path }</h2>
<h2>
<span className="main">
<a onClick={e => onPrefixClick(e, "")} href="">
{currentBucket}
</a>
</span>
{path}
</h2>
)
}
export default connect(state => {
const mapStateToProps = state => {
return {
currentBucket: state.currentBucket,
currentPath: state.currentPath
currentBucket: getCurrentBucket(state),
currentPrefix: state.objects.currentPrefix
}
})(Path)
}
const mapDispatchToProps = dispatch => {
return {
selectPrefix: prefix => dispatch(actionsObjects.selectPrefix(prefix))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Path)

View File

@@ -0,0 +1,45 @@
/*
* 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 ObjectItem from "./ObjectItem"
import * as actionsObjects from "../actions/objects"
export const PrefixContainer = ({ object, currentPrefix, selectPrefix }) => {
const props = {
name: object.name,
contentType: object.contentType,
onClick: () => selectPrefix(`${currentPrefix}${object.name}`)
}
return <ObjectItem {...props} />
}
const mapStateToProps = (state, ownProps) => {
return {
object: ownProps.object,
currentPrefix: state.objects.currentPrefix
}
}
const mapDispatchToProps = dispatch => {
return {
selectPrefix: prefix => dispatch(actionsObjects.selectPrefix(prefix))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(PrefixContainer)

View File

@@ -24,13 +24,15 @@ import Dropdown from "react-bootstrap/lib/Dropdown"
import BucketSearch from "./BucketSearch"
import BucketList from "./BucketList"
import Host from "./Host"
import * as actionsCommon from "../actions/common"
export const SideBar = () => {
export const SideBar = ({ sidebarOpen, clickOutside }) => {
return (
<ClickOutHandler>
<ClickOutHandler onClickOut={clickOutside}>
<div
className={classNames({
"fe-sidebar": true
"fe-sidebar": true,
toggled: sidebarOpen
})}
>
<div className="fes-header clearfix hidden-sm hidden-xs">
@@ -47,4 +49,16 @@ export const SideBar = () => {
)
}
export default connect(state => state)(SideBar)
const mapStateToProps = state => {
return {
sidebarOpen: state.common.sidebarOpen
}
}
const mapDispatchToProps = dispatch => {
return {
clickOutside: () => dispatch(actionsCommon.closeSidebar())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SideBar)

View File

@@ -0,0 +1,64 @@
/*
* 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 humanize from "humanize"
import * as actionsCommon from "../actions/common"
export class StorageInfo extends React.Component {
componentWillMount() {
const { fetchStorageInfo } = this.props
fetchStorageInfo()
}
render() {
const { total, free } = this.props.storageInfo
const used = total - free
const usedPercent = used / total * 100 + "%"
const freePercent = free * 100 / total
return (
<div className="feh-usage">
<div className="fehu-chart">
<div style={{ width: usedPercent }} />
</div>
<ul>
<li>
<span>Used: </span>
{humanize.filesize(total - free)}
</li>
<li className="pull-right">
<span>Free: </span>
{humanize.filesize(total - used)}
</li>
</ul>
</div>
)
}
}
const mapStateToProps = state => {
return {
storageInfo: state.common.storageInfo
}
}
const mapDispatchToProps = dispatch => {
return {
fetchStorageInfo: () => dispatch(actionsCommon.fetchStorageInfo())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(StorageInfo)

View File

@@ -0,0 +1,36 @@
/*
* 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 { MobileHeader } from "../MobileHeader"
describe("Bucket", () => {
it("should render without crashing", () => {
shallow(<MobileHeader sidebarOpen={false} />)
})
it("should toggleSidebar when trigger is clicked", () => {
const toggleSidebar = jest.fn()
const wrapper = shallow(
<MobileHeader sidebarOpen={false} toggleSidebar={toggleSidebar} />
)
wrapper
.find("#sidebar-toggle")
.simulate("click", { stopPropagation: jest.fn() })
expect(toggleSidebar).toHaveBeenCalled()
})
})

View File

@@ -0,0 +1,61 @@
/*
* 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 { ObjectsHeader } from "../ObjectsHeader"
describe("ObjectsHeader", () => {
it("should render without crashing", () => {
const sortObjects = jest.fn()
shallow(<ObjectsHeader sortObjects={sortObjects} />)
})
it("should render columns with asc classes by default", () => {
const sortObjects = jest.fn()
const wrapper = shallow(<ObjectsHeader sortObjects={sortObjects} />)
expect(
wrapper.find("#sort-by-name i").hasClass("fa-sort-alpha-asc")
).toBeTruthy()
expect(
wrapper.find("#sort-by-size i").hasClass("fa-sort-amount-asc")
).toBeTruthy()
expect(
wrapper.find("#sort-by-last-modified i").hasClass("fa-sort-numeric-asc")
).toBeTruthy()
})
it("should render name column with desc class when objects are sorted by name", () => {
const sortObjects = jest.fn()
const wrapper = shallow(
<ObjectsHeader sortObjects={sortObjects} sortNameOrder={true} />
)
expect(
wrapper.find("#sort-by-name i").hasClass("fa-sort-alpha-desc")
).toBeTruthy()
})
it("should call sortObjects when a column is clicked", () => {
const sortObjects = jest.fn()
const wrapper = shallow(<ObjectsHeader sortObjects={sortObjects} />)
wrapper.find("#sort-by-name").simulate("click")
expect(sortObjects).toHaveBeenCalledWith("name")
wrapper.find("#sort-by-size").simulate("click")
expect(sortObjects).toHaveBeenCalledWith("size")
wrapper.find("#sort-by-last-modified").simulate("click")
expect(sortObjects).toHaveBeenCalledWith("last-modified")
})
})

View File

@@ -0,0 +1,39 @@
/*
* 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 { ObjectsList } from "../ObjectsList"
describe("ObjectsList", () => {
it("should render without crashing", () => {
shallow(<ObjectsList objects={[]} />)
})
it("should render ObjectContainer for every object", () => {
const wrapper = shallow(
<ObjectsList objects={[{ name: "test1.jpg" }, { name: "test2.jpg" }]} />
)
expect(wrapper.find("ObjectContainer").length).toBe(2)
})
it("should render PrefixContainer for every prefix", () => {
const wrapper = shallow(
<ObjectsList objects={[{ name: "abc/" }, { name: "xyz/" }]} />
)
expect(wrapper.find("Connect(PrefixContainer)").length).toBe(2)
})
})

View File

@@ -0,0 +1,57 @@
/*
* 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 { ObjectsListContainer } from "../ObjectsListContainer"
describe("ObjectsList", () => {
it("should render without crashing", () => {
shallow(<ObjectsListContainer loadObjects={jest.fn()} />)
})
it("should render ObjectsList with objects", () => {
const wrapper = shallow(
<ObjectsListContainer
objects={[{ name: "test1.jpg" }, { name: "test2.jpg" }]}
loadObjects={jest.fn()}
/>
)
expect(wrapper.find("ObjectsList").length).toBe(1)
expect(wrapper.find("ObjectsList").prop("objects")).toEqual([
{ name: "test1.jpg" },
{ name: "test2.jpg" }
])
})
it("should call loadObjects when currentBucket is changed", () => {
const loadObjects = jest.fn()
const wrapper = shallow(
<ObjectsListContainer currentBucket="test1" loadObjects={loadObjects} />
)
wrapper.setProps({ currentBucket: "test2" })
expect(loadObjects).toHaveBeenCalled()
})
it("should call loadObjects when currentPrefix is changed", () => {
const loadObjects = jest.fn()
const wrapper = shallow(
<ObjectsListContainer currentPrefix="abc/" loadObjects={loadObjects} />
)
wrapper.setProps({ currentPrefix: "abc/xyz/" })
expect(loadObjects).toHaveBeenCalled()
})
})

View File

@@ -0,0 +1,37 @@
/*
* 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 { ObjectItem } from "../ObjectItem"
describe("ObjectItem", () => {
it("should render without crashing", () => {
shallow(<ObjectItem name={"test"} />)
})
it("should render with content type", () => {
const wrapper = shallow(<ObjectItem name={"test.jpg"} contentType={""} />)
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()
})
})

View File

@@ -0,0 +1,72 @@
/*
* 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 { Path } from "../Path"
describe("Path", () => {
it("should render without crashing", () => {
shallow(<Path currentBucket={"test1"} currentPrefix={"test2"} />)
})
it("should render only bucket if there is no prefix", () => {
const wrapper = shallow(<Path currentBucket={"test1"} currentPrefix={""} />)
expect(wrapper.find("span").length).toBe(1)
expect(wrapper.text()).toBe("test1")
})
it("should render bucket and prefix", () => {
const wrapper = shallow(
<Path currentBucket={"test1"} currentPrefix={"a/b/"} />
)
expect(wrapper.find("span").length).toBe(3)
expect(
wrapper
.find("span")
.at(0)
.text()
).toBe("test1")
expect(
wrapper
.find("span")
.at(1)
.text()
).toBe("a")
expect(
wrapper
.find("span")
.at(2)
.text()
).toBe("b")
})
it("should call selectPrefix when a prefix part is clicked", () => {
const selectPrefix = jest.fn()
const wrapper = shallow(
<Path
currentBucket={"test1"}
currentPrefix={"a/b/"}
selectPrefix={selectPrefix}
/>
)
wrapper
.find("a")
.at(2)
.simulate("click", { preventDefault: jest.fn() })
expect(selectPrefix).toHaveBeenCalledWith("a/b/")
})
})

View File

@@ -0,0 +1,44 @@
/*
* 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 { PrefixContainer } from "../PrefixContainer"
describe("PrefixContainer", () => {
it("should render without crashing", () => {
shallow(<PrefixContainer object={{ name: "abc/" }} />)
})
it("should render ObjectItem with props", () => {
const wrapper = shallow(<PrefixContainer object={{ name: "abc/" }} />)
expect(wrapper.find("ObjectItem").length).toBe(1)
expect(wrapper.find("ObjectItem").prop("name")).toBe("abc/")
})
it("should call selectPrefix when the prefix is clicked", () => {
const selectPrefix = jest.fn()
const wrapper = shallow(
<PrefixContainer
object={{ name: "abc/" }}
currentPrefix={"xyz/"}
selectPrefix={selectPrefix}
/>
)
wrapper.find("ObjectItem").prop("onClick")()
expect(selectPrefix).toHaveBeenCalledWith("xyz/abc/")
})
})

View File

@@ -0,0 +1,41 @@
/*
* 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 { StorageInfo } from "../StorageInfo"
describe("StorageInfo", () => {
it("should render without crashing", () => {
shallow(
<StorageInfo
storageInfo={{ total: 100, free: 60 }}
fetchStorageInfo={jest.fn()}
/>
)
})
it("should fetchStorageInfo before component is mounted", () => {
const fetchStorageInfo = jest.fn()
shallow(
<StorageInfo
storageInfo={{ total: 100, free: 60 }}
fetchStorageInfo={fetchStorageInfo}
/>
)
expect(fetchStorageInfo).toHaveBeenCalled()
})
})