mirror of
https://github.com/minio/minio.git
synced 2024-12-24 06:05:55 -05:00
Refactor of components (#5499)
This commit is contained in:
parent
9ab6a8035f
commit
feb726dd98
@ -28,14 +28,26 @@ const middlewares = [thunk]
|
||||
const mockStore = configureStore(middlewares)
|
||||
|
||||
describe("Buckets actions", () => {
|
||||
it("creates buckets/SET_LIST after fetching the buckets", () => {
|
||||
it("creates buckets/SET_LIST and buckets/SET_CURRENT_BUCKET after fetching the buckets", () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: "buckets/SET_LIST", buckets: ["test1", "test2"] }
|
||||
{ type: "buckets/SET_LIST", buckets: ["test1", "test2"] },
|
||||
{ type: "buckets/SET_CURRENT_BUCKET", bucket: "test1" }
|
||||
]
|
||||
return store.dispatch(actionsBuckets.fetchBuckets()).then(() => {
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
})
|
||||
})
|
||||
|
||||
it("should update browser url and creates buckets/SET_CURRENT_BUCKET action when selectBucket is called", () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: "buckets/SET_CURRENT_BUCKET", bucket: "test1" }
|
||||
]
|
||||
store.dispatch(actionsBuckets.selectBucket("test1"))
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
expect(window.location.pathname).toBe("/test1")
|
||||
})
|
||||
})
|
||||
|
41
browser/app/js/actions/__tests__/common.test.js
Normal file
41
browser/app/js/actions/__tests__/common.test.js
Normal 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 configureStore from "redux-mock-store"
|
||||
import thunk from "redux-thunk"
|
||||
import * as actionsCommon from "../common"
|
||||
|
||||
jest.mock("../../web", () => ({
|
||||
StorageInfo: jest.fn(() => {
|
||||
return Promise.resolve({ storageInfo: { Total: 100, Free: 60 } })
|
||||
})
|
||||
}))
|
||||
|
||||
const middlewares = [thunk]
|
||||
const mockStore = configureStore(middlewares)
|
||||
|
||||
describe("Common actions", () => {
|
||||
it("creates common/SET_STORAGE_INFO after fetching the storage details ", () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: "common/SET_STORAGE_INFO", storageInfo: { total: 100, free: 60 } }
|
||||
]
|
||||
return store.dispatch(actionsCommon.fetchStorageInfo()).then(() => {
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
})
|
||||
})
|
||||
})
|
171
browser/app/js/actions/__tests__/objects.test.js
Normal file
171
browser/app/js/actions/__tests__/objects.test.js
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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 configureStore from "redux-mock-store"
|
||||
import thunk from "redux-thunk"
|
||||
import * as actionsObjects from "../objects"
|
||||
|
||||
jest.mock("../../web", () => ({
|
||||
ListObjects: jest.fn(() => {
|
||||
return Promise.resolve({
|
||||
objects: [{ name: "test1" }, { name: "test2" }],
|
||||
istruncated: false,
|
||||
nextmarker: "test2"
|
||||
})
|
||||
})
|
||||
}))
|
||||
|
||||
const middlewares = [thunk]
|
||||
const mockStore = configureStore(middlewares)
|
||||
|
||||
describe("Objects actions", () => {
|
||||
it("creates objects/SET_LIST action", () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/SET_LIST",
|
||||
objects: [{ name: "test1" }, { name: "test2" }],
|
||||
isTruncated: false,
|
||||
marker: "test2"
|
||||
}
|
||||
]
|
||||
store.dispatch(
|
||||
actionsObjects.setList(
|
||||
[{ name: "test1" }, { name: "test2" }],
|
||||
"test2",
|
||||
false
|
||||
)
|
||||
)
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
})
|
||||
|
||||
it("creates objects/SET_SORT_BY action", () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/SET_SORT_BY",
|
||||
sortBy: "name"
|
||||
}
|
||||
]
|
||||
store.dispatch(actionsObjects.setSortBy("name"))
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
})
|
||||
|
||||
it("creates objects/SET_SORT_ORDER action", () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/SET_SORT_ORDER",
|
||||
sortOrder: true
|
||||
}
|
||||
]
|
||||
store.dispatch(actionsObjects.setSortOrder(true))
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
})
|
||||
|
||||
it("creates objects/SET_LIST after fetching the objects", () => {
|
||||
const store = mockStore({
|
||||
buckets: { currentBucket: "bk1" },
|
||||
objects: { currentPrefix: "" }
|
||||
})
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/SET_LIST",
|
||||
objects: [{ name: "test1" }, { name: "test2" }],
|
||||
marker: "test2",
|
||||
isTruncated: false
|
||||
},
|
||||
{
|
||||
type: "objects/SET_SORT_BY",
|
||||
sortBy: ""
|
||||
},
|
||||
{
|
||||
type: "objects/SET_SORT_ORDER",
|
||||
sortOrder: false
|
||||
}
|
||||
]
|
||||
return store.dispatch(actionsObjects.fetchObjects()).then(() => {
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
})
|
||||
})
|
||||
|
||||
it("creates objects/APPEND_LIST after fetching more objects", () => {
|
||||
const store = mockStore({
|
||||
buckets: { currentBucket: "bk1" },
|
||||
objects: { currentPrefix: "" }
|
||||
})
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/APPEND_LIST",
|
||||
objects: [{ name: "test1" }, { name: "test2" }],
|
||||
marker: "test2",
|
||||
isTruncated: false
|
||||
}
|
||||
]
|
||||
return store.dispatch(actionsObjects.fetchObjects(true)).then(() => {
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
})
|
||||
})
|
||||
|
||||
it("creates objects/SET_SORT_BY and objects/SET_SORT_ORDER when sortObjects is called", () => {
|
||||
const store = mockStore({
|
||||
objects: {
|
||||
list: [],
|
||||
sortBy: "",
|
||||
sortOrder: false,
|
||||
isTruncated: false,
|
||||
marker: ""
|
||||
}
|
||||
})
|
||||
const expectedActions = [
|
||||
{
|
||||
type: "objects/SET_SORT_BY",
|
||||
sortBy: "name"
|
||||
},
|
||||
{
|
||||
type: "objects/SET_SORT_ORDER",
|
||||
sortOrder: true
|
||||
},
|
||||
{
|
||||
type: "objects/SET_LIST",
|
||||
objects: [],
|
||||
isTruncated: false,
|
||||
marker: ""
|
||||
}
|
||||
]
|
||||
store.dispatch(actionsObjects.sortObjects("name"))
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
})
|
||||
|
||||
it("should update browser url and creates objects/SET_CURRENT_PREFIX action when selectPrefix is called", () => {
|
||||
const store = mockStore({
|
||||
buckets: { currentBucket: "test" }
|
||||
})
|
||||
const expectedActions = [
|
||||
{ type: "objects/SET_CURRENT_PREFIX", prefix: "abc/" }
|
||||
]
|
||||
store.dispatch(actionsObjects.selectPrefix("abc/"))
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
expect(window.location.pathname.endsWith("/test/abc/")).toBeTruthy()
|
||||
})
|
||||
})
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import web from "../web"
|
||||
import history from "../history"
|
||||
|
||||
export const SET_LIST = "buckets/SET_LIST"
|
||||
export const SET_FILTER = "buckets/SET_FILTER"
|
||||
@ -25,6 +26,9 @@ export const fetchBuckets = () => {
|
||||
return web.ListBuckets().then(res => {
|
||||
const buckets = res.buckets ? res.buckets.map(bucket => bucket.name) : []
|
||||
dispatch(setList(buckets))
|
||||
if (buckets.length > 0) {
|
||||
dispatch(selectBucket(buckets[0]))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -43,6 +47,13 @@ export const setFilter = filter => {
|
||||
}
|
||||
}
|
||||
|
||||
export const selectBucket = bucket => {
|
||||
return function(dispatch) {
|
||||
dispatch(setCurrentBucket(bucket))
|
||||
history.push(`/${bucket}`)
|
||||
}
|
||||
}
|
||||
|
||||
export const setCurrentBucket = bucket => {
|
||||
return {
|
||||
type: SET_CURRENT_BUCKET,
|
||||
|
46
browser/app/js/actions/common.js
Normal file
46
browser/app/js/actions/common.js
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 web from "../web"
|
||||
|
||||
export const TOGGLE_SIDEBAR = "common/TOGGLE_SIDEBAR"
|
||||
export const CLOSE_SIDEBAR = "common/CLOSE_SIDEBAR"
|
||||
export const SET_STORAGE_INFO = "common/SET_STORAGE_INFO"
|
||||
|
||||
export const toggleSidebar = () => ({
|
||||
type: TOGGLE_SIDEBAR
|
||||
})
|
||||
|
||||
export const closeSidebar = () => ({
|
||||
type: CLOSE_SIDEBAR
|
||||
})
|
||||
|
||||
export const fetchStorageInfo = () => {
|
||||
return function(dispatch) {
|
||||
return web.StorageInfo().then(res => {
|
||||
const storageInfo = {
|
||||
total: res.storageInfo.Total,
|
||||
free: res.storageInfo.Free
|
||||
}
|
||||
dispatch(setStorageInfo(storageInfo))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const setStorageInfo = storageInfo => ({
|
||||
type: SET_STORAGE_INFO,
|
||||
storageInfo
|
||||
})
|
126
browser/app/js/actions/objects.js
Normal file
126
browser/app/js/actions/objects.js
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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 web from "../web"
|
||||
import history from "../history"
|
||||
import {
|
||||
sortObjectsByName,
|
||||
sortObjectsBySize,
|
||||
sortObjectsByDate
|
||||
} from "../utils"
|
||||
|
||||
export const SET_LIST = "objects/SET_LIST"
|
||||
export const APPEND_LIST = "objects/APPEND_LIST"
|
||||
export const SET_SORT_BY = "objects/SET_SORT_BY"
|
||||
export const SET_SORT_ORDER = "objects/SET_SORT_ORDER"
|
||||
export const SET_CURRENT_PREFIX = "objects/SET_CURRENT_PREFIX"
|
||||
|
||||
export const setList = (objects, marker, isTruncated) => ({
|
||||
type: SET_LIST,
|
||||
objects,
|
||||
marker,
|
||||
isTruncated
|
||||
})
|
||||
|
||||
export const appendList = (objects, marker, isTruncated) => ({
|
||||
type: APPEND_LIST,
|
||||
objects,
|
||||
marker,
|
||||
isTruncated
|
||||
})
|
||||
|
||||
export const fetchObjects = append => {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
buckets: { currentBucket },
|
||||
objects: { currentPrefix, marker }
|
||||
} = getState()
|
||||
return web
|
||||
.ListObjects({
|
||||
bucketName: currentBucket,
|
||||
prefix: currentPrefix,
|
||||
marker: 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))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const sortObjects = sortBy => {
|
||||
return function(dispatch, getState) {
|
||||
const { objects } = getState()
|
||||
const sortOrder = objects.sortBy == sortBy ? !objects.sortOrder : true
|
||||
dispatch(setSortBy(sortBy))
|
||||
dispatch(setSortOrder(sortOrder))
|
||||
let list
|
||||
switch (sortBy) {
|
||||
case "name":
|
||||
list = sortObjectsByName(objects.list, sortOrder)
|
||||
break
|
||||
case "size":
|
||||
list = sortObjectsBySize(objects.list, sortOrder)
|
||||
break
|
||||
case "last-modified":
|
||||
list = sortObjectsByDate(objects.list, sortOrder)
|
||||
break
|
||||
default:
|
||||
list = objects.list
|
||||
break
|
||||
}
|
||||
dispatch(setList(list, objects.marker, objects.isTruncated))
|
||||
}
|
||||
}
|
||||
|
||||
export const setSortBy = sortBy => ({
|
||||
type: SET_SORT_BY,
|
||||
sortBy
|
||||
})
|
||||
|
||||
export const setSortOrder = sortOrder => ({
|
||||
type: SET_SORT_ORDER,
|
||||
sortOrder
|
||||
})
|
||||
|
||||
export const selectPrefix = prefix => {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(setCurrentPrefix(prefix))
|
||||
const currentBucket = getState().buckets.currentBucket
|
||||
history.replace(`/${currentBucket}/${prefix}`)
|
||||
}
|
||||
}
|
||||
|
||||
export const setCurrentPrefix = prefix => {
|
||||
return {
|
||||
type: SET_CURRENT_PREFIX,
|
||||
prefix
|
||||
}
|
||||
}
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
selectBucket: bucket => dispatch(actionsBuckets.setCurrentBucket(bucket))
|
||||
selectBucket: bucket => dispatch(actionsBuckets.selectBucket(bucket))
|
||||
}
|
||||
}
|
||||
|
||||
|
28
browser/app/js/components/Header.js
Normal file
28
browser/app/js/components/Header.js
Normal 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
|
30
browser/app/js/components/MainContent.js
Normal file
30
browser/app/js/components/MainContent.js
Normal 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
|
60
browser/app/js/components/MobileHeader.js
Normal file
60
browser/app/js/components/MobileHeader.js
Normal 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)
|
35
browser/app/js/components/ObjectContainer.js
Normal file
35
browser/app/js/components/ObjectContainer.js
Normal 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
|
58
browser/app/js/components/ObjectItem.js
Normal file
58
browser/app/js/components/ObjectItem.js
Normal 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
|
99
browser/app/js/components/ObjectsHeader.js
Normal file
99
browser/app/js/components/ObjectsHeader.js
Normal 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)
|
@ -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
|
||||
|
75
browser/app/js/components/ObjectsListContainer.js
Normal file
75
browser/app/js/components/ObjectsListContainer.js
Normal 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
|
||||
)
|
28
browser/app/js/components/ObjectsSection.js
Normal file
28
browser/app/js/components/ObjectsSection.js
Normal 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
|
@ -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)
|
||||
|
45
browser/app/js/components/PrefixContainer.js
Normal file
45
browser/app/js/components/PrefixContainer.js
Normal 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)
|
@ -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)
|
||||
|
64
browser/app/js/components/StorageInfo.js
Normal file
64
browser/app/js/components/StorageInfo.js
Normal 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)
|
36
browser/app/js/components/__tests__/MobileHeader.test.js
Normal file
36
browser/app/js/components/__tests__/MobileHeader.test.js
Normal 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()
|
||||
})
|
||||
})
|
61
browser/app/js/components/__tests__/ObjectsHeader.test.js
Normal file
61
browser/app/js/components/__tests__/ObjectsHeader.test.js
Normal 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")
|
||||
})
|
||||
})
|
39
browser/app/js/components/__tests__/ObjectsList.test.js
Normal file
39
browser/app/js/components/__tests__/ObjectsList.test.js
Normal 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)
|
||||
})
|
||||
})
|
@ -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()
|
||||
})
|
||||
})
|
37
browser/app/js/components/__tests__/ObjetctItem.test.js
Normal file
37
browser/app/js/components/__tests__/ObjetctItem.test.js
Normal 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()
|
||||
})
|
||||
})
|
72
browser/app/js/components/__tests__/Path.test.js
Normal file
72
browser/app/js/components/__tests__/Path.test.js
Normal 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/")
|
||||
})
|
||||
})
|
44
browser/app/js/components/__tests__/PrefixContainer.test.js
Normal file
44
browser/app/js/components/__tests__/PrefixContainer.test.js
Normal 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/")
|
||||
})
|
||||
})
|
41
browser/app/js/components/__tests__/StorageInfo.test.js
Normal file
41
browser/app/js/components/__tests__/StorageInfo.test.js
Normal 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()
|
||||
})
|
||||
})
|
@ -20,6 +20,6 @@
|
||||
var p = window.location.pathname
|
||||
export const minioBrowserPrefix = p.slice(0, p.indexOf("/", 1))
|
||||
|
||||
export const READ_ONLY = 'readonly'
|
||||
export const WRITE_ONLY = 'writeonly'
|
||||
export const READ_WRITE = 'readwrite'
|
||||
export const READ_ONLY = "readonly"
|
||||
export const WRITE_ONLY = "writeonly"
|
||||
export const READ_WRITE = "readwrite"
|
||||
|
24
browser/app/js/history.js
Normal file
24
browser/app/js/history.js
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 createHistory from "history/createBrowserHistory"
|
||||
import { minioBrowserPrefix } from "./constants"
|
||||
|
||||
const history = createHistory({
|
||||
basename: minioBrowserPrefix
|
||||
})
|
||||
|
||||
export default history
|
@ -19,7 +19,8 @@ import * as actions from "../../actions/buckets"
|
||||
|
||||
describe("buckets reducer", () => {
|
||||
it("should return the initial state", () => {
|
||||
expect(reducer(undefined, {})).toEqual({
|
||||
const initialState = reducer(undefined, {})
|
||||
expect(initialState).toEqual({
|
||||
list: [],
|
||||
filter: "",
|
||||
currentBucket: ""
|
||||
@ -27,38 +28,26 @@ describe("buckets reducer", () => {
|
||||
})
|
||||
|
||||
it("should handle SET_BUCKETS", () => {
|
||||
expect(
|
||||
reducer(undefined, { type: actions.SET_LIST, buckets: ["bk1", "bk2"] })
|
||||
).toEqual({
|
||||
list: ["bk1", "bk2"],
|
||||
filter: "",
|
||||
currentBucket: ""
|
||||
const newState = reducer(undefined, {
|
||||
type: actions.SET_LIST,
|
||||
buckets: ["bk1", "bk2"]
|
||||
})
|
||||
expect(newState.list).toEqual(["bk1", "bk2"])
|
||||
})
|
||||
|
||||
it("should handle SET_BUCKETS_FILTER", () => {
|
||||
expect(
|
||||
reducer(undefined, {
|
||||
type: actions.SET_FILTER,
|
||||
filter: "test"
|
||||
})
|
||||
).toEqual({
|
||||
list: [],
|
||||
filter: "test",
|
||||
currentBucket: ""
|
||||
const newState = reducer(undefined, {
|
||||
type: actions.SET_FILTER,
|
||||
filter: "test"
|
||||
})
|
||||
expect(newState.filter).toEqual("test")
|
||||
})
|
||||
|
||||
it("should handle SELECT_BUCKET", () => {
|
||||
expect(
|
||||
reducer(undefined, {
|
||||
type: actions.SET_CURRENT_BUCKET,
|
||||
bucket: "test"
|
||||
})
|
||||
).toEqual({
|
||||
list: [],
|
||||
filter: "",
|
||||
currentBucket: "test"
|
||||
const newState = reducer(undefined, {
|
||||
type: actions.SET_CURRENT_BUCKET,
|
||||
bucket: "test"
|
||||
})
|
||||
expect(newState.currentBucket).toEqual("test")
|
||||
})
|
||||
})
|
||||
|
70
browser/app/js/reducers/__tests__/common.test.js
Normal file
70
browser/app/js/reducers/__tests__/common.test.js
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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 reducer from "../common"
|
||||
import * as actionsCommon from "../../actions/common"
|
||||
|
||||
describe("common reducer", () => {
|
||||
it("should return the initial state", () => {
|
||||
expect(reducer(undefined, {})).toEqual({
|
||||
sidebarOpen: false,
|
||||
storageInfo: {
|
||||
total: 0,
|
||||
free: 0
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle TOGGLE_SIDEBAR", () => {
|
||||
expect(
|
||||
reducer(
|
||||
{ sidebarOpen: false },
|
||||
{
|
||||
type: actionsCommon.TOGGLE_SIDEBAR
|
||||
}
|
||||
)
|
||||
).toEqual({
|
||||
sidebarOpen: true
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle CLOSE_SIDEBAR", () => {
|
||||
expect(
|
||||
reducer(
|
||||
{ sidebarOpen: true },
|
||||
{
|
||||
type: actionsCommon.CLOSE_SIDEBAR
|
||||
}
|
||||
)
|
||||
).toEqual({
|
||||
sidebarOpen: false
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle SET_STORAGE_INFO", () => {
|
||||
expect(
|
||||
reducer(
|
||||
{},
|
||||
{
|
||||
type: actionsCommon.SET_STORAGE_INFO,
|
||||
storageInfo: { total: 100, free: 40 }
|
||||
}
|
||||
)
|
||||
).toEqual({
|
||||
storageInfo: { total: 100, free: 40 }
|
||||
})
|
||||
})
|
||||
})
|
97
browser/app/js/reducers/__tests__/objects.test.js
Normal file
97
browser/app/js/reducers/__tests__/objects.test.js
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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 reducer from "../objects"
|
||||
import * as actions from "../../actions/objects"
|
||||
|
||||
describe("objects reducer", () => {
|
||||
it("should return the initial state", () => {
|
||||
const initialState = reducer(undefined, {})
|
||||
expect(initialState).toEqual({
|
||||
list: [],
|
||||
sortBy: "",
|
||||
sortOrder: false,
|
||||
currentPrefix: "",
|
||||
marker: "",
|
||||
isTruncated: false
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle SET_LIST", () => {
|
||||
const newState = reducer(undefined, {
|
||||
type: actions.SET_LIST,
|
||||
objects: [{ name: "obj1" }, { name: "obj2" }],
|
||||
marker: "obj2",
|
||||
isTruncated: false
|
||||
})
|
||||
expect(newState.list).toEqual([{ name: "obj1" }, { name: "obj2" }])
|
||||
expect(newState.marker).toBe("obj2")
|
||||
expect(newState.isTruncated).toBeFalsy()
|
||||
})
|
||||
|
||||
it("should handle APPEND_LIST", () => {
|
||||
const newState = reducer(
|
||||
{
|
||||
list: [{ name: "obj1" }, { name: "obj2" }],
|
||||
marker: "obj2",
|
||||
isTruncated: true
|
||||
},
|
||||
{
|
||||
type: actions.APPEND_LIST,
|
||||
objects: [{ name: "obj3" }, { name: "obj4" }],
|
||||
marker: "obj4",
|
||||
isTruncated: false
|
||||
}
|
||||
)
|
||||
expect(newState.list).toEqual([
|
||||
{ name: "obj1" },
|
||||
{ name: "obj2" },
|
||||
{ name: "obj3" },
|
||||
{ name: "obj4" }
|
||||
])
|
||||
expect(newState.marker).toBe("obj4")
|
||||
expect(newState.isTruncated).toBeFalsy()
|
||||
})
|
||||
|
||||
it("should handle SET_SORT_BY", () => {
|
||||
const newState = reducer(undefined, {
|
||||
type: actions.SET_SORT_BY,
|
||||
sortBy: "name"
|
||||
})
|
||||
expect(newState.sortBy).toEqual("name")
|
||||
})
|
||||
|
||||
it("should handle SET_SORT_ORDER", () => {
|
||||
const newState = reducer(undefined, {
|
||||
type: actions.SET_SORT_ORDER,
|
||||
sortOrder: true
|
||||
})
|
||||
expect(newState.sortOrder).toEqual(true)
|
||||
})
|
||||
|
||||
it("should handle SET_CURRENT_PREFIX", () => {
|
||||
const newState = reducer(
|
||||
{ currentPrefix: "test1/", marker: "abc", isTruncated: true },
|
||||
{
|
||||
type: actions.SET_CURRENT_PREFIX,
|
||||
prefix: "test2/"
|
||||
}
|
||||
)
|
||||
expect(newState.currentPrefix).toEqual("test2/")
|
||||
expect(newState.marker).toEqual("")
|
||||
expect(newState.isTruncated).toBeFalsy()
|
||||
})
|
||||
})
|
39
browser/app/js/reducers/common.js
Normal file
39
browser/app/js/reducers/common.js
Normal 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 * as actionsCommon from "../actions/common"
|
||||
|
||||
export default (
|
||||
state = { sidebarOpen: false, storageInfo: { total: 0, free: 0 } },
|
||||
action
|
||||
) => {
|
||||
switch (action.type) {
|
||||
case actionsCommon.TOGGLE_SIDEBAR:
|
||||
return Object.assign({}, state, {
|
||||
sidebarOpen: !state.sidebarOpen
|
||||
})
|
||||
case actionsCommon.CLOSE_SIDEBAR:
|
||||
return Object.assign({}, state, {
|
||||
sidebarOpen: false
|
||||
})
|
||||
case actionsCommon.SET_STORAGE_INFO:
|
||||
return Object.assign({}, state, {
|
||||
storageInfo: action.storageInfo
|
||||
})
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
@ -15,12 +15,16 @@
|
||||
*/
|
||||
|
||||
import { combineReducers } from "redux"
|
||||
import common from "./common"
|
||||
import alert from "./alert"
|
||||
import buckets from "./buckets"
|
||||
import objects from "./objects"
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
common,
|
||||
alert,
|
||||
buckets
|
||||
buckets,
|
||||
objects
|
||||
})
|
||||
|
||||
export default rootReducer
|
||||
|
65
browser/app/js/reducers/objects.js
Normal file
65
browser/app/js/reducers/objects.js
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 * as actionsObjects from "../actions/objects"
|
||||
|
||||
export default (
|
||||
state = {
|
||||
list: [],
|
||||
sortBy: "",
|
||||
sortOrder: false,
|
||||
currentPrefix: "",
|
||||
marker: "",
|
||||
isTruncated: false
|
||||
},
|
||||
action
|
||||
) => {
|
||||
switch (action.type) {
|
||||
case actionsObjects.SET_LIST:
|
||||
return {
|
||||
...state,
|
||||
list: action.objects,
|
||||
marker: action.marker,
|
||||
isTruncated: action.isTruncated
|
||||
}
|
||||
case actionsObjects.APPEND_LIST:
|
||||
return {
|
||||
...state,
|
||||
list: [...state.list, ...action.objects],
|
||||
marker: action.marker,
|
||||
isTruncated: action.isTruncated
|
||||
}
|
||||
case actionsObjects.SET_SORT_BY:
|
||||
return {
|
||||
...state,
|
||||
sortBy: action.sortBy
|
||||
}
|
||||
case actionsObjects.SET_SORT_ORDER:
|
||||
return {
|
||||
...state,
|
||||
sortOrder: action.sortOrder
|
||||
}
|
||||
case actionsObjects.SET_CURRENT_PREFIX:
|
||||
return {
|
||||
...state,
|
||||
currentPrefix: action.prefix,
|
||||
marker: "",
|
||||
isTruncated: false
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
@ -27,6 +27,13 @@
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
&:after {
|
||||
content: '/';
|
||||
margin: 0 4px;
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,10 @@
|
||||
},
|
||||
"jest": {
|
||||
"setupTestFrameworkScriptFile": "./app/js/jest/setup.js",
|
||||
"testURL": "https://localhost:8080"
|
||||
"testURL": "https://localhost:8080",
|
||||
"moduleNameMapper": {
|
||||
"\\.(css|scss|svg)$": "identity-obj-proxy"
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -60,6 +63,7 @@
|
||||
"font-awesome": "^4.7.0",
|
||||
"history": "^4.7.2",
|
||||
"humanize": "0.0.9",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"json-loader": "^0.5.4",
|
||||
"local-storage-fallback": "^4.0.2",
|
||||
"material-design-iconic-font": "^2.2.0",
|
||||
|
@ -2992,6 +2992,10 @@ har-validator@~5.0.3:
|
||||
ajv "^5.1.0"
|
||||
har-schema "^2.0.0"
|
||||
|
||||
harmony-reflect@^1.4.6:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.5.1.tgz#b54ca617b00cc8aef559bbb17b3d85431dc7e329"
|
||||
|
||||
has-ansi@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
|
||||
@ -3271,6 +3275,12 @@ icss-replace-symbols@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
|
||||
|
||||
identity-obj-proxy@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz#94d2bda96084453ef36fbc5aaec37e0f79f1fc14"
|
||||
dependencies:
|
||||
harmony-reflect "^1.4.6"
|
||||
|
||||
ieee754@^1.1.4:
|
||||
version "1.1.8"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
|
||||
|
Loading…
Reference in New Issue
Block a user