mirror of
https://github.com/minio/minio.git
synced 2025-03-20 12:34:16 -04:00
feature preview of image-objects (#9239)
This commit is contained in:
parent
a78731a3ba
commit
2bbc6a83e8
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
65
browser/app/js/objects/PreviewObjectModal.js
Normal file
65
browser/app/js/objects/PreviewObjectModal.js
Normal 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
|
@ -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(
|
||||||
|
@ -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,18 +48,18 @@ 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 = () => {
|
||||||
@ -67,16 +67,16 @@ export const fetchObjects = () => {
|
|||||||
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,7 +123,7 @@ 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
|
||||||
@ -149,17 +149,17 @@ 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())
|
||||||
@ -169,19 +169,19 @@ 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())
|
||||||
@ -189,25 +189,25 @@ export const deleteObject = 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 = () => {
|
||||||
@ -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,17 +276,16 @@ 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())
|
||||||
@ -295,43 +294,64 @@ 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 = () => {
|
||||||
@ -340,7 +360,7 @@ export const downloadCheckedObjects = () => {
|
|||||||
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,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -378,7 +396,7 @@ const downloadZip = (url, req, dispatch) => {
|
|||||||
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 ? "-" : ""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user