diff --git a/browser/app/js/alert/AlertContainer.js b/browser/app/js/alert/AlertContainer.js
new file mode 100644
index 000000000..a36e9910d
--- /dev/null
+++ b/browser/app/js/alert/AlertContainer.js
@@ -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 { connect } from "react-redux"
+import Alert from "./Alert"
+import * as alertActions from "./actions"
+
+export const AlertContainer = ({ alert, clearAlert }) => {
+ if (!alert.message) {
+ return ""
+ }
+ return
+}
+
+const mapStateToProps = state => {
+ return {
+ alert: state.alert
+ }
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ clearAlert: () => dispatch(alertActions.clear())
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(AlertContainer)
diff --git a/browser/app/js/alert/__tests___/Alert.test.js b/browser/app/js/alert/__tests___/Alert.test.js
index 5b8e3a492..b3041d8f6 100644
--- a/browser/app/js/alert/__tests___/Alert.test.js
+++ b/browser/app/js/alert/__tests___/Alert.test.js
@@ -26,7 +26,7 @@ describe("Alert", () => {
it("should call onDismiss when close button is clicked", () => {
const onDismiss = jest.fn()
const wrapper = mount(
-
+
)
wrapper.find("button").simulate("click", { preventDefault: jest.fn() })
expect(onDismiss).toHaveBeenCalled()
diff --git a/browser/app/js/alert/__tests___/AlertContainer.test.js b/browser/app/js/alert/__tests___/AlertContainer.test.js
new file mode 100644
index 000000000..d41bc6f02
--- /dev/null
+++ b/browser/app/js/alert/__tests___/AlertContainer.test.js
@@ -0,0 +1,34 @@
+/*
+ * 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, mount } from "enzyme"
+import { AlertContainer } from "../AlertContainer"
+
+describe("Alert", () => {
+ it("should render without crashing", () => {
+ shallow(
+
+ )
+ })
+
+ it("should render nothing if message is empty", () => {
+ const wrapper = shallow(
+
+ )
+ expect(wrapper.find("Alert").length).toBe(0)
+ })
+})
diff --git a/browser/app/js/browser/Browser.js b/browser/app/js/browser/Browser.js
index f2fb5c5f9..a469351f7 100644
--- a/browser/app/js/browser/Browser.js
+++ b/browser/app/js/browser/Browser.js
@@ -19,6 +19,7 @@ import classNames from "classnames"
import { connect } from "react-redux"
import SideBar from "./SideBar"
import MainContent from "./MainContent"
+import AlertContainer from "../alert/AlertContainer"
class Browser extends React.Component {
render() {
@@ -30,6 +31,7 @@ class Browser extends React.Component {
>
+
)
}
diff --git a/browser/app/js/components/ConfirmModal.js b/browser/app/js/browser/ConfirmModal.js
similarity index 51%
rename from browser/app/js/components/ConfirmModal.js
rename to browser/app/js/browser/ConfirmModal.js
index 3677c3bbd..7fd4a2d20 100644
--- a/browser/app/js/components/ConfirmModal.js
+++ b/browser/app/js/browser/ConfirmModal.js
@@ -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,33 +14,40 @@
* limitations under the License.
*/
-import React from 'react'
-import Modal from 'react-bootstrap/lib/Modal'
-import ModalBody from 'react-bootstrap/lib/ModalBody'
+import React from "react"
+import { Modal, ModalBody } from "react-bootstrap"
-let ConfirmModal = ({baseClass, icon, text, sub, okText, cancelText, okHandler, cancelHandler, show}) => {
+let ConfirmModal = ({
+ baseClass,
+ icon,
+ text,
+ sub,
+ okText,
+ cancelText,
+ okHandler,
+ cancelHandler,
+ show
+}) => {
return (
-
+
-
-
-
- { text }
-
-
- { sub }
+
+
{text}
+
{sub}
-
diff --git a/browser/app/js/browser/MainActions.js b/browser/app/js/browser/MainActions.js
new file mode 100644
index 000000000..996a1339b
--- /dev/null
+++ b/browser/app/js/browser/MainActions.js
@@ -0,0 +1,83 @@
+/*
+ * Minio Cloud Storage (C) 2018 Minio, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from "react"
+import { connect } from "react-redux"
+import { Dropdown, OverlayTrigger, Tooltip } from "react-bootstrap"
+import * as actionsBuckets from "../buckets/actions"
+import * as uploadsActions from "../uploads/actions"
+
+export const MainActions = ({ uploadFile, showMakeBucketModal }) => {
+ const uploadTooltip = Upload file
+ const makeBucketTooltip = (
+ Create bucket
+ )
+ const onFileUpload = e => {
+ e.preventDefault()
+ uploadFile(e.target.files[0])
+ e.target.value = null
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ e.preventDefault()
+ showMakeBucketModal()
+ }}
+ >
+
+
+
+
+
+ )
+}
+
+const mapStateToProps = state => state
+
+const mapDispatchToProps = dispatch => {
+ return {
+ uploadFile: file => dispatch(uploadsActions.uploadFile(file)),
+ showMakeBucketModal: () => dispatch(actionsBuckets.showMakeBucketModal())
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(MainActions)
diff --git a/browser/app/js/browser/MainContent.js b/browser/app/js/browser/MainContent.js
index 46b728901..08f8bfb0d 100644
--- a/browser/app/js/browser/MainContent.js
+++ b/browser/app/js/browser/MainContent.js
@@ -18,12 +18,18 @@ import React from "react"
import MobileHeader from "./MobileHeader"
import Header from "./Header"
import ObjectsSection from "../objects/ObjectsSection"
+import MainActions from "./MainActions"
+import MakeBucketModal from "../buckets/MakeBucketModal"
+import UploadModal from "../uploads/UploadModal"
export const MainContent = () => (
+
+
+
)
diff --git a/browser/app/js/browser/__tests__/MainActions.test.js b/browser/app/js/browser/__tests__/MainActions.test.js
new file mode 100644
index 000000000..88ff84144
--- /dev/null
+++ b/browser/app/js/browser/__tests__/MainActions.test.js
@@ -0,0 +1,47 @@
+/*
+ * 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, mount } from "enzyme"
+import { MainActions } from "../MainActions"
+
+describe("MainActions", () => {
+ it("should render without crashing", () => {
+ shallow()
+ })
+
+ it("should call showMakeBucketModal when create bucket icon is clicked", () => {
+ const showMakeBucketModal = jest.fn()
+ const wrapper = shallow(
+
+ )
+ wrapper
+ .find("#show-make-bucket")
+ .simulate("click", { preventDefault: jest.fn() })
+ expect(showMakeBucketModal).toHaveBeenCalled()
+ })
+
+ it("should call uploadFile when a file is selected for upload", () => {
+ const uploadFile = jest.fn()
+ const wrapper = shallow()
+ const file = new Blob(["file content"], { type: "text/plain" })
+ wrapper.find("#file-input").simulate("change", {
+ preventDefault: jest.fn(),
+ target: { files: [file] }
+ })
+ expect(uploadFile).toHaveBeenCalledWith(file)
+ })
+})
diff --git a/browser/app/js/buckets/MakeBucketModal.js b/browser/app/js/buckets/MakeBucketModal.js
new file mode 100644
index 000000000..a16645801
--- /dev/null
+++ b/browser/app/js/buckets/MakeBucketModal.js
@@ -0,0 +1,90 @@
+/*
+ * 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 { Modal, ModalBody } from "react-bootstrap"
+import * as actionsBuckets from "./actions"
+
+export class MakeBucketModal extends React.Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ bucketName: ""
+ }
+ }
+ onSubmit(e) {
+ e.preventDefault()
+ const { makeBucket } = this.props
+ const bucket = this.state.bucketName
+ if (bucket) {
+ makeBucket(bucket)
+ this.hideModal()
+ }
+ }
+ hideModal() {
+ this.setState({
+ bucketName: ""
+ })
+ this.props.hideMakeBucketModal()
+ }
+ render() {
+ const { showMakeBucketModal } = this.props
+ return (
+
+
+ ×
+
+
+
+
+
+ )
+ }
+}
+
+const mapStateToProps = state => {
+ return {
+ showMakeBucketModal: state.buckets.showMakeBucketModal
+ }
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ makeBucket: bucket => dispatch(actionsBuckets.makeBucket(bucket)),
+ hideMakeBucketModal: () => dispatch(actionsBuckets.hideMakeBucketModal())
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(MakeBucketModal)
diff --git a/browser/app/js/buckets/__tests__/MakeBucketModal.test.js b/browser/app/js/buckets/__tests__/MakeBucketModal.test.js
new file mode 100644
index 000000000..1d956ac79
--- /dev/null
+++ b/browser/app/js/buckets/__tests__/MakeBucketModal.test.js
@@ -0,0 +1,80 @@
+/*
+ * 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, mount } from "enzyme"
+import { MakeBucketModal } from "../MakeBucketModal"
+
+describe("MakeBucketModal", () => {
+ it("should render without crashing", () => {
+ shallow()
+ })
+
+ it("should call hideMakeBucketModal when close button is clicked", () => {
+ const hideMakeBucketModal = jest.fn()
+ const wrapper = shallow(
+
+ )
+ wrapper.find("button").simulate("click")
+ expect(hideMakeBucketModal).toHaveBeenCalled()
+ })
+
+ it("bucketName should be cleared before hiding the modal", () => {
+ const hideMakeBucketModal = jest.fn()
+ const wrapper = shallow(
+
+ )
+ wrapper.find("input").simulate("change", {
+ target: { value: "test" }
+ })
+ expect(wrapper.state("bucketName")).toBe("test")
+ wrapper.find("button").simulate("click")
+ expect(wrapper.state("bucketName")).toBe("")
+ })
+
+ it("should call makeBucket when the form is submitted", () => {
+ const makeBucket = jest.fn()
+ const hideMakeBucketModal = jest.fn()
+ const wrapper = shallow(
+
+ )
+ wrapper.find("input").simulate("change", {
+ target: { value: "test" }
+ })
+ wrapper.find("form").simulate("submit", { preventDefault: jest.fn() })
+ expect(makeBucket).toHaveBeenCalledWith("test")
+ })
+
+ it("should call hideMakeBucketModal and clear bucketName after the form is submited", () => {
+ const makeBucket = jest.fn()
+ const hideMakeBucketModal = jest.fn()
+ const wrapper = shallow(
+
+ )
+ wrapper.find("input").simulate("change", {
+ target: { value: "test" }
+ })
+ wrapper.find("form").simulate("submit", { preventDefault: jest.fn() })
+ expect(hideMakeBucketModal).toHaveBeenCalled()
+ expect(wrapper.state("bucketName")).toBe("")
+ })
+})
diff --git a/browser/app/js/buckets/__tests__/actions.test.js b/browser/app/js/buckets/__tests__/actions.test.js
index e56d8a8c1..d5b80521c 100644
--- a/browser/app/js/buckets/__tests__/actions.test.js
+++ b/browser/app/js/buckets/__tests__/actions.test.js
@@ -17,13 +17,21 @@
import configureStore from "redux-mock-store"
import thunk from "redux-thunk"
import * as actionsBuckets from "../actions"
+import * as objectActions from "../../objects/actions"
jest.mock("../../web", () => ({
ListBuckets: jest.fn(() => {
return Promise.resolve({ buckets: [{ name: "test1" }, { name: "test2" }] })
+ }),
+ MakeBucket: jest.fn(() => {
+ return Promise.resolve()
})
}))
+jest.mock("../../objects/actions", () => ({
+ selectPrefix: () => dispatch => {}
+}))
+
const middlewares = [thunk]
const mockStore = configureStore(middlewares)
@@ -40,24 +48,6 @@ describe("Buckets actions", () => {
})
})
- it("creates buckets/SET_LIST directly", () => {
- const store = mockStore()
- const expectedActions = [
- { type: "buckets/SET_LIST", buckets: ["test1", "test2"] }
- ]
- store.dispatch(actionsBuckets.setList(["test1", "test2"]))
- const actions = store.getActions()
- expect(actions).toEqual(expectedActions)
- })
-
- it("creates buckets/SET_FILTER directly", () => {
- const store = mockStore()
- const expectedActions = [{ type: "buckets/SET_FILTER", filter: "test" }]
- store.dispatch(actionsBuckets.setFilter("test"))
- 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 = [
@@ -68,4 +58,44 @@ describe("Buckets actions", () => {
expect(actions).toEqual(expectedActions)
expect(window.location.pathname).toBe("/test1")
})
+
+ it("creates buckets/SHOW_MAKE_BUCKET_MODAL for showMakeBucketModal", () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: "buckets/SHOW_MAKE_BUCKET_MODAL", show: true }
+ ]
+ store.dispatch(actionsBuckets.showMakeBucketModal())
+ const actions = store.getActions()
+ expect(actions).toEqual(expectedActions)
+ })
+
+ it("creates buckets/SHOW_MAKE_BUCKET_MODAL for hideMakeBucketModal", () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: "buckets/SHOW_MAKE_BUCKET_MODAL", show: false }
+ ]
+ store.dispatch(actionsBuckets.hideMakeBucketModal())
+ const actions = store.getActions()
+ expect(actions).toEqual(expectedActions)
+ })
+
+ it("creates buckets/ADD action", () => {
+ const store = mockStore()
+ const expectedActions = [{ type: "buckets/ADD", bucket: "test" }]
+ store.dispatch(actionsBuckets.addBucket("test"))
+ const actions = store.getActions()
+ expect(actions).toEqual(expectedActions)
+ })
+
+ it("creates buckets/ADD and buckets/SET_CURRENT_BUCKET after creating the bucket", () => {
+ const store = mockStore()
+ const expectedActions = [
+ { type: "buckets/ADD", bucket: "test1" },
+ { type: "buckets/SET_CURRENT_BUCKET", bucket: "test1" }
+ ]
+ return store.dispatch(actionsBuckets.makeBucket("test1")).then(() => {
+ const actions = store.getActions()
+ expect(actions).toEqual(expectedActions)
+ })
+ })
})
diff --git a/browser/app/js/buckets/__tests__/reducer.test.js b/browser/app/js/buckets/__tests__/reducer.test.js
index 298389af0..6906198e2 100644
--- a/browser/app/js/buckets/__tests__/reducer.test.js
+++ b/browser/app/js/buckets/__tests__/reducer.test.js
@@ -23,7 +23,8 @@ describe("buckets reducer", () => {
expect(initialState).toEqual({
list: [],
filter: "",
- currentBucket: ""
+ currentBucket: "",
+ showMakeBucketModal: false
})
})
@@ -35,6 +36,17 @@ describe("buckets reducer", () => {
expect(newState.list).toEqual(["bk1", "bk2"])
})
+ it("should handle ADD", () => {
+ const newState = reducer(
+ { list: ["test1", "test2"] },
+ {
+ type: actions.ADD,
+ bucket: "test3"
+ }
+ )
+ expect(newState.list).toEqual(["test3", "test1", "test2"])
+ })
+
it("should handle SET_FILTER", () => {
const newState = reducer(undefined, {
type: actions.SET_FILTER,
@@ -50,4 +62,12 @@ describe("buckets reducer", () => {
})
expect(newState.currentBucket).toEqual("test")
})
+
+ it("should handle SHOW_MAKE_BUCKET_MODAL", () => {
+ const newState = reducer(undefined, {
+ type: actions.SHOW_MAKE_BUCKET_MODAL,
+ show: true
+ })
+ expect(newState.showMakeBucketModal).toBeTruthy()
+ })
})
diff --git a/browser/app/js/buckets/actions.js b/browser/app/js/buckets/actions.js
index 01b40f778..250dd839d 100644
--- a/browser/app/js/buckets/actions.js
+++ b/browser/app/js/buckets/actions.js
@@ -16,10 +16,14 @@
import web from "../web"
import history from "../history"
+import * as alertActions from "../alert/actions"
+import * as objectsActions from "../objects/actions"
export const SET_LIST = "buckets/SET_LIST"
+export const ADD = "buckets/ADD"
export const SET_FILTER = "buckets/SET_FILTER"
export const SET_CURRENT_BUCKET = "buckets/SET_CURRENT_BUCKET"
+export const SHOW_MAKE_BUCKET_MODAL = "buckets/SHOW_MAKE_BUCKET_MODAL"
export const fetchBuckets = () => {
return function(dispatch) {
@@ -50,6 +54,7 @@ export const setFilter = filter => {
export const selectBucket = bucket => {
return function(dispatch) {
dispatch(setCurrentBucket(bucket))
+ dispatch(objectsActions.selectPrefix(""))
history.push(`/${bucket}`)
}
}
@@ -60,3 +65,39 @@ export const setCurrentBucket = bucket => {
bucket
}
}
+
+export const makeBucket = bucket => {
+ return function(dispatch) {
+ return web
+ .MakeBucket({
+ bucketName: bucket
+ })
+ .then(() => {
+ dispatch(addBucket(bucket))
+ dispatch(selectBucket(bucket))
+ })
+ .catch(err =>
+ dispatch(
+ alertActions.set({
+ type: "danger",
+ message: err.message
+ })
+ )
+ )
+ }
+}
+
+export const addBucket = bucket => ({
+ type: ADD,
+ bucket
+})
+
+export const showMakeBucketModal = () => ({
+ type: SHOW_MAKE_BUCKET_MODAL,
+ show: true
+})
+
+export const hideMakeBucketModal = () => ({
+ type: SHOW_MAKE_BUCKET_MODAL,
+ show: false
+})
diff --git a/browser/app/js/buckets/reducer.js b/browser/app/js/buckets/reducer.js
index 69be47e34..7bebdef21 100644
--- a/browser/app/js/buckets/reducer.js
+++ b/browser/app/js/buckets/reducer.js
@@ -17,7 +17,12 @@
import * as actionsBuckets from "./actions"
export default (
- state = { list: [], filter: "", currentBucket: "" },
+ state = {
+ list: [],
+ filter: "",
+ currentBucket: "",
+ showMakeBucketModal: false
+ },
action
) => {
switch (action.type) {
@@ -26,6 +31,11 @@ export default (
...state,
list: action.buckets
}
+ case actionsBuckets.ADD:
+ return {
+ ...state,
+ list: [action.bucket, ...state.list]
+ }
case actionsBuckets.SET_FILTER:
return {
...state,
@@ -36,6 +46,11 @@ export default (
...state,
currentBucket: action.bucket
}
+ case actionsBuckets.SHOW_MAKE_BUCKET_MODAL:
+ return {
+ ...state,
+ showMakeBucketModal: action.show
+ }
default:
return state
}
diff --git a/browser/app/js/components/UploadModal.js b/browser/app/js/components/UploadModal.js
deleted file mode 100644
index f68b32ee8..000000000
--- a/browser/app/js/components/UploadModal.js
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Minio Cloud Storage (C) 2016 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 classNames from 'classnames'
-import connect from 'react-redux/lib/components/connect'
-
-import ProgressBar from 'react-bootstrap/lib/ProgressBar'
-import ConfirmModal from './ConfirmModal'
-
-import * as actions from '../actions'
-
-// UploadModal is a modal that handles multiple file uploads.
-// During the upload, it displays a progress bar, and can transform into an
-// abort modal if the user decides to abort the uploads.
-class UploadModal extends React.Component {
-
- // Abort all the current uploads.
- abortUploads(e) {
- e.preventDefault()
- const {dispatch, uploads} = this.props
-
- for (var slug in uploads) {
- let upload = uploads[slug]
- upload.xhr.abort()
- dispatch(actions.stopUpload({
- slug
- }))
- }
-
- this.hideAbort(e)
- }
-
- // Show the abort modal instead of the progress modal.
- showAbort(e) {
- e.preventDefault()
- const {dispatch} = this.props
-
- dispatch(actions.setShowAbortModal(true))
- }
-
- // Show the progress modal instead of the abort modal.
- hideAbort(e) {
- e.preventDefault()
- const {dispatch} = this.props
-
- dispatch(actions.setShowAbortModal(false))
- }
-
- render() {
- const {uploads, showAbortModal} = this.props
-
- // Show the abort modal.
- if (showAbortModal) {
- let baseClass = classNames({
- 'abort-upload': true
- })
- let okIcon = classNames({
- 'fa': true,
- 'fa-times': true
- })
- let cancelIcon = classNames({
- 'fa': true,
- 'fa-cloud-upload': true
- })
-
- return (
-
-
- )
- }
-
- // If we don't have any files uploading, don't show anything.
- let numberUploading = Object.keys(uploads).length
- if (numberUploading == 0)
- return ( )
-
- let totalLoaded = 0
- let totalSize = 0
-
- // Iterate over each upload, adding together the total size and that
- // which has been uploaded.
- for (var slug in uploads) {
- let upload = uploads[slug]
- totalLoaded += upload.loaded
- totalSize += upload.size
- }
-
- let percent = (totalLoaded / totalSize) * 100
-
- // If more than one: "Uploading files (5)..."
- // If only one: "Uploading myfile.txt..."
- let text = 'Uploading ' + (numberUploading == 1 ? `'${uploads[Object.keys(uploads)[0]].name}'` : `files (${numberUploading})`) + '...'
-
- return (
-