feature preview of image-objects (#9239)

This commit is contained in:
tweigel-dev 2020-04-08 19:47:47 +02:00 committed by GitHub
parent a78731a3ba
commit 2bbc6a83e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 316 additions and 116 deletions

View File

@ -14,30 +14,67 @@
* limitations under the License. * limitations under the License.
*/ */
import mimedb from 'mime-types' import mimedb from "mime-types"
const isFolder = (name, contentType) => { const isFolder = (name, contentType) => {
if (name.endsWith('/')) return true if (name.endsWith("/")) return true
return false return false
} }
const isPdf = (name, contentType) => { const isPdf = (name, contentType) => {
if (contentType === 'application/pdf') return true if (contentType === "application/pdf") return true
return false
}
const isImage = (name, contentType) => {
if (
contentType === "image/jpeg" ||
contentType === "image/gif" ||
contentType === "image/x-icon" ||
contentType === "image/png" ||
contentType === "image/svg+xml" ||
contentType === "image/tiff" ||
contentType === "image/webp"
)
return true
return false return false
} }
const isZip = (name, contentType) => { const isZip = (name, contentType) => {
if (!contentType || !contentType.includes('/')) return false if (!contentType || !contentType.includes("/")) return false
if (contentType.split('/')[1].includes('zip')) return true if (contentType.split("/")[1].includes("zip")) return true
return false return false
} }
const isCode = (name, contentType) => { const isCode = (name, contentType) => {
const codeExt = ['c', 'cpp', 'go', 'py', 'java', 'rb', 'js', 'pl', 'fs', const codeExt = [
'php', 'css', 'less', 'scss', 'coffee', 'net', 'html', "c",
'rs', 'exs', 'scala', 'hs', 'clj', 'el', 'scm', 'lisp', "cpp",
'asp', 'aspx'] "go",
const ext = name.split('.').reverse()[0] "py",
"java",
"rb",
"js",
"pl",
"fs",
"php",
"css",
"less",
"scss",
"coffee",
"net",
"html",
"rs",
"exs",
"scala",
"hs",
"clj",
"el",
"scm",
"lisp",
"asp",
"aspx",
]
const ext = name.split(".").reverse()[0]
for (var i in codeExt) { for (var i in codeExt) {
if (ext === codeExt[i]) return true if (ext === codeExt[i]) return true
} }
@ -45,9 +82,9 @@ const isCode = (name, contentType) => {
} }
const isExcel = (name, contentType) => { const isExcel = (name, contentType) => {
if (!contentType || !contentType.includes('/')) return false if (!contentType || !contentType.includes("/")) return false
const types = ['excel', 'spreadsheet'] const types = ["excel", "spreadsheet"]
const subType = contentType.split('/')[1] const subType = contentType.split("/")[1]
for (var i in types) { for (var i in types) {
if (subType.includes(types[i])) return true if (subType.includes(types[i])) return true
} }
@ -55,9 +92,9 @@ const isExcel = (name, contentType) => {
} }
const isDoc = (name, contentType) => { const isDoc = (name, contentType) => {
if (!contentType || !contentType.includes('/')) return false if (!contentType || !contentType.includes("/")) return false
const types = ['word', '.document'] const types = ["word", ".document"]
const subType = contentType.split('/')[1] const subType = contentType.split("/")[1]
for (var i in types) { for (var i in types) {
if (subType.includes(types[i])) return true if (subType.includes(types[i])) return true
} }
@ -65,9 +102,9 @@ const isDoc = (name, contentType) => {
} }
const isPresentation = (name, contentType) => { const isPresentation = (name, contentType) => {
if (!contentType || !contentType.includes('/')) return false if (!contentType || !contentType.includes("/")) return false
var types = ['powerpoint', 'presentation'] var types = ["powerpoint", "presentation"]
const subType = contentType.split('/')[1] const subType = contentType.split("/")[1]
for (var i in types) { for (var i in types) {
if (subType.includes(types[i])) return true if (subType.includes(types[i])) return true
} }
@ -76,31 +113,32 @@ const isPresentation = (name, contentType) => {
const typeToIcon = (type) => { const typeToIcon = (type) => {
return (name, contentType) => { return (name, contentType) => {
if (!contentType || !contentType.includes('/')) return false if (!contentType || !contentType.includes("/")) return false
if (contentType.split('/')[0] === type) return true if (contentType.split("/")[0] === type) return true
return false return false
} }
} }
export const getDataType = (name, contentType) => { export const getDataType = (name, contentType) => {
if (contentType === "") { if (contentType === "") {
contentType = mimedb.lookup(name) || 'application/octet-stream' contentType = mimedb.lookup(name) || "application/octet-stream"
} }
const check = [ const check = [
['folder', isFolder], ["folder", isFolder],
['code', isCode], ["code", isCode],
['audio', typeToIcon('audio')], ["audio", typeToIcon("audio")],
['image', typeToIcon('image')], ["image", typeToIcon("image")],
['video', typeToIcon('video')], ["video", typeToIcon("video")],
['text', typeToIcon('text')], ["text", typeToIcon("text")],
['pdf', isPdf], ["pdf", isPdf],
['zip', isZip], ["image", isImage],
['excel', isExcel], ["zip", isZip],
['doc', isDoc], ["excel", isExcel],
['presentation', isPresentation] ["doc", isDoc],
["presentation", isPresentation],
] ]
for (var i in check) { for (var i in check) {
if (check[i][1](name, contentType)) return check[i][0] if (check[i][1](name, contentType)) return check[i][0]
} }
return 'other' return "other"
} }

View File

@ -19,18 +19,22 @@ import { connect } from "react-redux"
import { Dropdown } from "react-bootstrap" import { Dropdown } from "react-bootstrap"
import ShareObjectModal from "./ShareObjectModal" import ShareObjectModal from "./ShareObjectModal"
import DeleteObjectConfirmModal from "./DeleteObjectConfirmModal" import DeleteObjectConfirmModal from "./DeleteObjectConfirmModal"
import PreviewObjectModal from "./PreviewObjectModal"
import * as objectsActions from "./actions" import * as objectsActions from "./actions"
import { getDataType } from "../mime.js"
import { import {
SHARE_OBJECT_EXPIRY_DAYS, SHARE_OBJECT_EXPIRY_DAYS,
SHARE_OBJECT_EXPIRY_HOURS, SHARE_OBJECT_EXPIRY_HOURS,
SHARE_OBJECT_EXPIRY_MINUTES SHARE_OBJECT_EXPIRY_MINUTES,
} from "../constants" } from "../constants"
export class ObjectActions extends React.Component { export class ObjectActions extends React.Component {
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { this.state = {
showDeleteConfirmation: false showDeleteConfirmation: false,
showPreview: false,
} }
} }
shareObject(e) { shareObject(e) {
@ -53,7 +57,20 @@ export class ObjectActions extends React.Component {
} }
hideDeleteConfirmModal() { hideDeleteConfirmModal() {
this.setState({ this.setState({
showDeleteConfirmation: false showDeleteConfirmation: false,
})
}
getObjectURL(objectname, callback) {
const { getObjectURL } = this.props
getObjectURL(objectname, callback)
}
showPreviewModal(e) {
e.preventDefault()
this.setState({ showPreview: true })
}
hidePreviewModal() {
this.setState({
showPreview: false,
}) })
} }
render() { render() {
@ -69,6 +86,15 @@ export class ObjectActions extends React.Component {
> >
<i className="fas fa-share-alt" /> <i className="fas fa-share-alt" />
</a> </a>
{getDataType(object.name, object.contentType) == "image" && (
<a
href=""
className="fiad-action"
onClick={this.showPreviewModal.bind(this)}
>
<i className="far fa-file-image" />
</a>
)}
<a <a
href="" href=""
className="fiad-action" className="fiad-action"
@ -77,14 +103,22 @@ export class ObjectActions extends React.Component {
<i className="fas fa-trash-alt" /> <i className="fas fa-trash-alt" />
</a> </a>
</Dropdown.Menu> </Dropdown.Menu>
{(showShareObjectModal && shareObjectName === object.name) && {showShareObjectModal && shareObjectName === object.name && (
<ShareObjectModal object={object} />} <ShareObjectModal object={object} />
)}
{this.state.showDeleteConfirmation && ( {this.state.showDeleteConfirmation && (
<DeleteObjectConfirmModal <DeleteObjectConfirmModal
deleteObject={this.deleteObject.bind(this)} deleteObject={this.deleteObject.bind(this)}
hideDeleteConfirmModal={this.hideDeleteConfirmModal.bind(this)} hideDeleteConfirmModal={this.hideDeleteConfirmModal.bind(this)}
/> />
)} )}
{this.state.showPreview && (
<PreviewObjectModal
object={object}
hidePreviewModal={this.hidePreviewModal.bind(this)}
getObjectURL={this.getObjectURL.bind(this)}
/>
)}
</Dropdown> </Dropdown>
) )
} }
@ -94,15 +128,17 @@ const mapStateToProps = (state, ownProps) => {
return { return {
object: ownProps.object, object: ownProps.object,
showShareObjectModal: state.objects.shareObject.show, showShareObjectModal: state.objects.shareObject.show,
shareObjectName: state.objects.shareObject.object shareObjectName: state.objects.shareObject.object,
} }
} }
const mapDispatchToProps = dispatch => { const mapDispatchToProps = (dispatch) => {
return { return {
shareObject: (object, days, hours, minutes) => shareObject: (object, days, hours, minutes) =>
dispatch(objectsActions.shareObject(object, days, hours, minutes)), dispatch(objectsActions.shareObject(object, days, hours, minutes)),
deleteObject: object => dispatch(objectsActions.deleteObject(object)) deleteObject: (object) => dispatch(objectsActions.deleteObject(object)),
getObjectURL: (object, callback) =>
dispatch(objectsActions.getObjectURL(object, callback)),
} }
} }

View File

@ -0,0 +1,65 @@
/*
* MinIO Cloud Storage (C) 2020 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 { Modal, ModalHeader, ModalBody } from "react-bootstrap"
class PreviewObjectModal extends React.Component {
constructor(props) {
super(props)
this.state = {
url: "",
}
props.getObjectURL(props.object.name, (url) => {
this.setState({
url: url,
})
})
}
render() {
const { hidePreviewModal } = this.props
return (
<Modal
show={true}
animation={false}
onHide={hidePreviewModal}
bsSize="large"
>
<ModalHeader>Object Preview</ModalHeader>
<ModalBody>
<div className="input-group">
{this.state.url && (
<img
alt="Image broken"
src={this.state.url}
style={{ display: "block", width: "100%" }}
/>
)}
</div>
</ModalBody>
<div className="modal-footer">
{
<button className="btn btn-link" onClick={hidePreviewModal}>
Cancel
</button>
}
</div>
</Modal>
)
}
}
export default PreviewObjectModal

View File

@ -66,6 +66,49 @@ describe("ObjectActions", () => {
expect(deleteObject).toHaveBeenCalledWith("obj1") expect(deleteObject).toHaveBeenCalledWith("obj1")
}) })
it("should show PreviewObjectModal when preview action is clicked", () => {
const wrapper = shallow(
<ObjectActions
object={{ name: "obj1", contentType: "image/jpeg"}}
currentPrefix={"pre1/"} />
)
wrapper
.find("a")
.at(1)
.simulate("click", { preventDefault: jest.fn() })
expect(wrapper.state("showPreview")).toBeTruthy()
expect(wrapper.find("PreviewObjectModal").length).toBe(1)
})
it("should hide PreviewObjectModal when cancel button is clicked", () => {
const wrapper = shallow(
<ObjectActions
object={{ name: "obj1" , contentType: "image/jpeg"}}
currentPrefix={"pre1/"} />
)
wrapper
.find("a")
.at(1)
.simulate("click", { preventDefault: jest.fn() })
wrapper.find("PreviewObjectModal").prop("hidePreviewModal")()
wrapper.update()
expect(wrapper.state("showPreview")).toBeFalsy()
expect(wrapper.find("PreviewObjectModal").length).toBe(0)
})
it("should not show PreviewObjectModal when preview action is clicked if object is not an image", () => {
const wrapper = shallow(
<ObjectActions
object={{ name: "obj1"}}
currentPrefix={"pre1/"} />
)
expect(wrapper
.find("a")
.length).toBe(2) // find only the other 2
})
it("should call shareObject with object and expiry", () => { it("should call shareObject with object and expiry", () => {
const shareObject = jest.fn() const shareObject = jest.fn()
const wrapper = shallow( const wrapper = shallow(

View File

@ -19,7 +19,7 @@ import history from "../history"
import { import {
sortObjectsByName, sortObjectsByName,
sortObjectsBySize, sortObjectsBySize,
sortObjectsByDate sortObjectsByDate,
} from "../utils" } from "../utils"
import { getCurrentBucket } from "../buckets/selectors" import { getCurrentBucket } from "../buckets/selectors"
import { getCurrentPrefix, getCheckedList } from "./selectors" import { getCurrentPrefix, getCheckedList } from "./selectors"
@ -31,7 +31,7 @@ import {
SORT_BY_SIZE, SORT_BY_SIZE,
SORT_BY_LAST_MODIFIED, SORT_BY_LAST_MODIFIED,
SORT_ORDER_ASC, SORT_ORDER_ASC,
SORT_ORDER_DESC SORT_ORDER_DESC,
} from "../constants" } from "../constants"
export const SET_LIST = "objects/SET_LIST" export const SET_LIST = "objects/SET_LIST"
@ -48,35 +48,35 @@ export const CHECKED_LIST_REMOVE = "objects/CHECKED_LIST_REMOVE"
export const CHECKED_LIST_RESET = "objects/CHECKED_LIST_RESET" export const CHECKED_LIST_RESET = "objects/CHECKED_LIST_RESET"
export const SET_LIST_LOADING = "objects/SET_LIST_LOADING" export const SET_LIST_LOADING = "objects/SET_LIST_LOADING"
export const setList = objects => ({ export const setList = (objects) => ({
type: SET_LIST, type: SET_LIST,
objects objects,
}) })
export const resetList = () => ({ export const resetList = () => ({
type: RESET_LIST type: RESET_LIST,
}) })
export const setListLoading = listLoading => ({ export const setListLoading = (listLoading) => ({
type: SET_LIST_LOADING, type: SET_LIST_LOADING,
listLoading listLoading,
}) })
export const fetchObjects = () => { export const fetchObjects = () => {
return function(dispatch, getState) { return function (dispatch, getState) {
dispatch(resetList()) dispatch(resetList())
const { const {
buckets: { currentBucket }, buckets: { currentBucket },
objects: { currentPrefix } objects: { currentPrefix },
} = getState() } = getState()
if (currentBucket) { if (currentBucket) {
dispatch(setListLoading(true)) dispatch(setListLoading(true))
return web return web
.ListObjects({ .ListObjects({
bucketName: currentBucket, bucketName: currentBucket,
prefix: currentPrefix prefix: currentPrefix,
}) })
.then(res => { .then((res) => {
// we need to check if the bucket name and prefix are the same as // we need to check if the bucket name and prefix are the same as
// when the request was made before updating the displayed objects // when the request was made before updating the displayed objects
if ( if (
@ -85,10 +85,10 @@ export const fetchObjects = () => {
) { ) {
let objects = [] let objects = []
if (res.objects) { if (res.objects) {
objects = res.objects.map(object => { objects = res.objects.map((object) => {
return { return {
...object, ...object,
name: object.name.replace(currentPrefix, "") name: object.name.replace(currentPrefix, ""),
} }
}) })
} }
@ -104,13 +104,13 @@ export const fetchObjects = () => {
dispatch(setListLoading(false)) dispatch(setListLoading(false))
} }
}) })
.catch(err => { .catch((err) => {
if (web.LoggedIn()) { if (web.LoggedIn()) {
dispatch( dispatch(
alertActions.set({ alertActions.set({
type: "danger", type: "danger",
message: err.message, message: err.message,
autoClear: true autoClear: true,
}) })
) )
dispatch(resetList()) dispatch(resetList())
@ -123,8 +123,8 @@ export const fetchObjects = () => {
} }
} }
export const sortObjects = sortBy => { export const sortObjects = (sortBy) => {
return function(dispatch, getState) { return function (dispatch, getState) {
const { objects } = getState() const { objects } = getState()
let sortOrder = SORT_ORDER_ASC let sortOrder = SORT_ORDER_ASC
// Reverse sort order if the list is already sorted on same field // Reverse sort order if the list is already sorted on same field
@ -149,18 +149,18 @@ const sortObjectsList = (list, sortBy, sortOrder) => {
} }
} }
export const setSortBy = sortBy => ({ export const setSortBy = (sortBy) => ({
type: SET_SORT_BY, type: SET_SORT_BY,
sortBy sortBy,
}) })
export const setSortOrder = sortOrder => ({ export const setSortOrder = (sortOrder) => ({
type: SET_SORT_ORDER, type: SET_SORT_ORDER,
sortOrder sortOrder,
}) })
export const selectPrefix = prefix => { export const selectPrefix = (prefix) => {
return function(dispatch, getState) { return function (dispatch, getState) {
dispatch(setCurrentPrefix(prefix)) dispatch(setCurrentPrefix(prefix))
dispatch(fetchObjects()) dispatch(fetchObjects())
dispatch(resetCheckedList()) dispatch(resetCheckedList())
@ -169,49 +169,49 @@ export const selectPrefix = prefix => {
} }
} }
export const setCurrentPrefix = prefix => { export const setCurrentPrefix = (prefix) => {
return { return {
type: SET_CURRENT_PREFIX, type: SET_CURRENT_PREFIX,
prefix prefix,
} }
} }
export const setPrefixWritable = prefixWritable => ({ export const setPrefixWritable = (prefixWritable) => ({
type: SET_PREFIX_WRITABLE, type: SET_PREFIX_WRITABLE,
prefixWritable prefixWritable,
}) })
export const deleteObject = object => { export const deleteObject = (object) => {
return function(dispatch, getState) { return function (dispatch, getState) {
const currentBucket = getCurrentBucket(getState()) const currentBucket = getCurrentBucket(getState())
const currentPrefix = getCurrentPrefix(getState()) const currentPrefix = getCurrentPrefix(getState())
const objectName = `${currentPrefix}${object}` const objectName = `${currentPrefix}${object}`
return web return web
.RemoveObject({ .RemoveObject({
bucketName: currentBucket, bucketName: currentBucket,
objects: [objectName] objects: [objectName],
}) })
.then(() => { .then(() => {
dispatch(removeObject(object)) dispatch(removeObject(object))
}) })
.catch(e => { .catch((e) => {
dispatch( dispatch(
alertActions.set({ alertActions.set({
type: "danger", type: "danger",
message: e.message message: e.message,
}) })
) )
}) })
} }
} }
export const removeObject = object => ({ export const removeObject = (object) => ({
type: REMOVE, type: REMOVE,
object object,
}) })
export const deleteCheckedObjects = () => { export const deleteCheckedObjects = () => {
return function(dispatch, getState) { return function (dispatch, getState) {
const checkedObjects = getCheckedList(getState()) const checkedObjects = getCheckedList(getState())
for (let i = 0; i < checkedObjects.length; i++) { for (let i = 0; i < checkedObjects.length; i++) {
dispatch(deleteObject(checkedObjects[i])) dispatch(deleteObject(checkedObjects[i]))
@ -221,7 +221,7 @@ export const deleteCheckedObjects = () => {
} }
export const shareObject = (object, days, hours, minutes) => { export const shareObject = (object, days, hours, minutes) => {
return function(dispatch, getState) { return function (dispatch, getState) {
const currentBucket = getCurrentBucket(getState()) const currentBucket = getCurrentBucket(getState())
const currentPrefix = getCurrentPrefix(getState()) const currentPrefix = getCurrentPrefix(getState())
const objectName = `${currentPrefix}${object}` const objectName = `${currentPrefix}${object}`
@ -232,22 +232,22 @@ export const shareObject = (object, days, hours, minutes) => {
host: location.host, host: location.host,
bucket: currentBucket, bucket: currentBucket,
object: objectName, object: objectName,
expiry: expiry expiry: expiry,
}) })
.then(obj => { .then((obj) => {
dispatch(showShareObject(object, obj.url)) dispatch(showShareObject(object, obj.url))
dispatch( dispatch(
alertActions.set({ alertActions.set({
type: "success", type: "success",
message: `Object shared. Expires in ${days} days ${hours} hours ${minutes} minutes` message: `Object shared. Expires in ${days} days ${hours} hours ${minutes} minutes`,
}) })
) )
}) })
.catch(err => { .catch((err) => {
dispatch( dispatch(
alertActions.set({ alertActions.set({
type: "danger", type: "danger",
message: err.message message: err.message,
}) })
) )
}) })
@ -265,7 +265,7 @@ export const shareObject = (object, days, hours, minutes) => {
dispatch( dispatch(
alertActions.set({ alertActions.set({
type: "success", type: "success",
message: `Object shared.` message: `Object shared.`,
}) })
) )
} }
@ -276,18 +276,17 @@ export const showShareObject = (object, url) => ({
type: SET_SHARE_OBJECT, type: SET_SHARE_OBJECT,
show: true, show: true,
object, object,
url url,
}) })
export const hideShareObject = (object, url) => ({ export const hideShareObject = (object, url) => ({
type: SET_SHARE_OBJECT, type: SET_SHARE_OBJECT,
show: false, show: false,
object: "", object: "",
url: "" url: "",
}) })
export const getObjectURL = (object, callback) => {
export const downloadObject = object => { return function (dispatch, getState) {
return function(dispatch, getState) {
const currentBucket = getCurrentBucket(getState()) const currentBucket = getCurrentBucket(getState())
const currentPrefix = getCurrentPrefix(getState()) const currentPrefix = getCurrentPrefix(getState())
const objectName = `${currentPrefix}${object}` const objectName = `${currentPrefix}${object}`
@ -295,52 +294,73 @@ export const downloadObject = object => {
if (web.LoggedIn()) { if (web.LoggedIn()) {
return web return web
.CreateURLToken() .CreateURLToken()
.then(res => { .then((res) => {
const url = `${ const url = `${window.location.origin}${minioBrowserPrefix}/download/${currentBucket}/${encObjectName}?token=${res.token}`
window.location.origin callback(url)
}${minioBrowserPrefix}/download/${currentBucket}/${encObjectName}?token=${
res.token
}`
window.location = url
}) })
.catch(err => { .catch((err) => {
dispatch( dispatch(
alertActions.set({ alertActions.set({
type: "danger", type: "danger",
message: err.message message: err.message,
}) })
) )
}) })
} else { } else {
const url = `${ const url = `${window.location.origin}${minioBrowserPrefix}/download/${currentBucket}/${encObjectName}?token=`
window.location.origin callback(url)
}${minioBrowserPrefix}/download/${currentBucket}/${encObjectName}?token=` }
}
}
export const downloadObject = (object) => {
return function (dispatch, getState) {
const currentBucket = getCurrentBucket(getState())
const currentPrefix = getCurrentPrefix(getState())
const objectName = `${currentPrefix}${object}`
const encObjectName = encodeURI(objectName)
if (web.LoggedIn()) {
return web
.CreateURLToken()
.then((res) => {
const url = `${window.location.origin}${minioBrowserPrefix}/download/${currentBucket}/${encObjectName}?token=${res.token}`
window.location = url
})
.catch((err) => {
dispatch(
alertActions.set({
type: "danger",
message: err.message,
})
)
})
} else {
const url = `${window.location.origin}${minioBrowserPrefix}/download/${currentBucket}/${encObjectName}?token=`
window.location = url window.location = url
} }
} }
} }
export const checkObject = object => ({ export const checkObject = (object) => ({
type: CHECKED_LIST_ADD, type: CHECKED_LIST_ADD,
object object,
}) })
export const uncheckObject = object => ({ export const uncheckObject = (object) => ({
type: CHECKED_LIST_REMOVE, type: CHECKED_LIST_REMOVE,
object object,
}) })
export const resetCheckedList = () => ({ export const resetCheckedList = () => ({
type: CHECKED_LIST_RESET type: CHECKED_LIST_RESET,
}) })
export const downloadCheckedObjects = () => { export const downloadCheckedObjects = () => {
return function(dispatch, getState) { return function (dispatch, getState) {
const state = getState() const state = getState()
const req = { const req = {
bucketName: getCurrentBucket(state), bucketName: getCurrentBucket(state),
prefix: getCurrentPrefix(state), prefix: getCurrentPrefix(state),
objects: getCheckedList(state) objects: getCheckedList(state),
} }
if (!web.LoggedIn()) { if (!web.LoggedIn()) {
const requestUrl = location.origin + "/minio/zip?token=" const requestUrl = location.origin + "/minio/zip?token="
@ -348,17 +368,15 @@ export const downloadCheckedObjects = () => {
} else { } else {
return web return web
.CreateURLToken() .CreateURLToken()
.then(res => { .then((res) => {
const requestUrl = `${ const requestUrl = `${location.origin}${minioBrowserPrefix}/zip?token=${res.token}`
location.origin
}${minioBrowserPrefix}/zip?token=${res.token}`
downloadZip(requestUrl, req, dispatch) downloadZip(requestUrl, req, dispatch)
}) })
.catch(err => .catch((err) =>
dispatch( dispatch(
alertActions.set({ alertActions.set({
type: "danger", type: "danger",
message: err.message message: err.message,
}) })
) )
) )
@ -374,11 +392,11 @@ const downloadZip = (url, req, dispatch) => {
xhr.open("POST", url, true) xhr.open("POST", url, true)
xhr.responseType = "blob" xhr.responseType = "blob"
xhr.onload = function(e) { xhr.onload = function (e) {
if (this.status == 200) { if (this.status == 200) {
dispatch(resetCheckedList()) dispatch(resetCheckedList())
var blob = new Blob([this.response], { var blob = new Blob([this.response], {
type: "octet/stream" type: "octet/stream",
}) })
var blobUrl = window.URL.createObjectURL(blob) var blobUrl = window.URL.createObjectURL(blob)
var separator = req.prefix.length > 1 ? "-" : "" var separator = req.prefix.length > 1 ? "-" : ""