mirror of
https://github.com/minio/minio.git
synced 2024-12-24 06:05:55 -05:00
allow non-loggedin users to access public bucket (#5570)
* conditionally render main action buttons - Make bucket action will be available only for loggedIn users - File upload button will be avaialble for loggedIn users and non-loggedIn users if the prefix is writable * select the bucket and prefix from the url When the url contains bucket and prefix, it will be selected by default instead of the first bucket from the list. * show BucketSearch only for LoggedIn users * allow non-LoggedIn users to access public bucket * removed unused Router imports * fix test case failures in BucketList.test.js * remove dupicate minioBrowserPrefix from url since history is already initialized with minioBrowserPrefix, no need to use it in push or replace * remove unused match from App component * remove unused minioBrowserPrefix imports
This commit is contained in:
parent
bb0adea494
commit
416841869a
@ -21,10 +21,10 @@ import "material-design-iconic-font/dist/css/material-design-iconic-font.min.css
|
||||
|
||||
import React from "react"
|
||||
import ReactDOM from "react-dom"
|
||||
import { BrowserRouter, Route } from "react-router-dom"
|
||||
import { Router, Route } from "react-router-dom"
|
||||
import { Provider } from "react-redux"
|
||||
|
||||
import { minioBrowserPrefix } from "./js/constants"
|
||||
import history from "./js/history"
|
||||
import configureStore from "./js/store/configure-store"
|
||||
import hideLoader from "./js/loader"
|
||||
import App from "./js/App"
|
||||
@ -33,9 +33,9 @@ const store = configureStore()
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<Route path={minioBrowserPrefix} component={App} />
|
||||
</BrowserRouter>
|
||||
<Router history={history}>
|
||||
<App />
|
||||
</Router>
|
||||
</Provider>,
|
||||
document.getElementById("root")
|
||||
)
|
||||
|
@ -34,13 +34,15 @@ const AuthorizedRoute = ({ component: Component, ...rest }) => (
|
||||
/>
|
||||
)
|
||||
|
||||
export const App = ({ match }) => (
|
||||
<Switch>
|
||||
<AuthorizedRoute exact path={match.url} component={Browser} />
|
||||
<Route path={`${match.url}/login`} component={Login} />
|
||||
<AuthorizedRoute path={`${match.url}/:bucket/*`} component={Browser} />
|
||||
<AuthorizedRoute path={`${match.url}/:bucket`} component={Browser} />
|
||||
</Switch>
|
||||
)
|
||||
export const App = () => {
|
||||
return (
|
||||
<Switch>
|
||||
<AuthorizedRoute exact path={"/"} component={Browser} />
|
||||
<Route path={"/login"} component={Login} />
|
||||
<Route path={"/:bucket/*"} component={Browser} />
|
||||
<Route path={"/:bucket"} component={Browser} />
|
||||
</Switch>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
|
@ -21,7 +21,6 @@ import logo from "../../img/logo.svg"
|
||||
import Alert from "../alert/Alert"
|
||||
import * as actionsAlert from "../alert/actions"
|
||||
import InputGroup from "./InputGroup"
|
||||
import { minioBrowserPrefix } from "../constants"
|
||||
import web from "../web"
|
||||
import { Redirect } from "react-router-dom"
|
||||
|
||||
@ -46,7 +45,7 @@ export class Login extends React.Component {
|
||||
password: document.getElementById("secretKey").value
|
||||
})
|
||||
.then(res => {
|
||||
history.push(minioBrowserPrefix)
|
||||
history.push("/")
|
||||
})
|
||||
.catch(e => {
|
||||
showAlert("danger", e.message)
|
||||
@ -67,7 +66,7 @@ export class Login extends React.Component {
|
||||
render() {
|
||||
const { clearAlert, alert } = this.props
|
||||
if (web.LoggedIn()) {
|
||||
return <Redirect to={minioBrowserPrefix} />
|
||||
return <Redirect to={"/"} />
|
||||
}
|
||||
let alertBox = <Alert {...alert} onDismiss={clearAlert} />
|
||||
// Make sure you don't show a fading out alert box on the initial web-page load.
|
||||
|
@ -17,10 +17,16 @@
|
||||
import React from "react"
|
||||
import { connect } from "react-redux"
|
||||
import { Dropdown, OverlayTrigger, Tooltip } from "react-bootstrap"
|
||||
import web from "../web"
|
||||
import * as actionsBuckets from "../buckets/actions"
|
||||
import * as uploadsActions from "../uploads/actions"
|
||||
import { getPrefixWritable } from "../objects/selectors"
|
||||
|
||||
export const MainActions = ({ uploadFile, showMakeBucketModal }) => {
|
||||
export const MainActions = ({
|
||||
prefixWritable,
|
||||
uploadFile,
|
||||
showMakeBucketModal
|
||||
}) => {
|
||||
const uploadTooltip = <Tooltip id="tt-upload-file">Upload file</Tooltip>
|
||||
const makeBucketTooltip = (
|
||||
<Tooltip id="tt-create-bucket">Create bucket</Tooltip>
|
||||
@ -31,47 +37,59 @@ export const MainActions = ({ uploadFile, showMakeBucketModal }) => {
|
||||
e.target.value = null
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown dropup className="feb-actions" id="fe-action-toggle">
|
||||
<Dropdown.Toggle noCaret className="feba-toggle">
|
||||
<span>
|
||||
<i className="fa fa-plus" />
|
||||
</span>
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu>
|
||||
<OverlayTrigger placement="left" overlay={uploadTooltip}>
|
||||
<a href="#" className="feba-btn feba-upload">
|
||||
<input
|
||||
type="file"
|
||||
onChange={onFileUpload}
|
||||
style={{ display: "none" }}
|
||||
id="file-input"
|
||||
/>
|
||||
<label htmlFor="file-input">
|
||||
{" "}
|
||||
<i className="fa fa-cloud-upload" />{" "}
|
||||
</label>
|
||||
</a>
|
||||
</OverlayTrigger>
|
||||
<OverlayTrigger placement="left" overlay={makeBucketTooltip}>
|
||||
<a
|
||||
href="#"
|
||||
id="show-make-bucket"
|
||||
className="feba-btn feba-bucket"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
showMakeBucketModal()
|
||||
}}
|
||||
>
|
||||
<i className="fa fa-hdd-o" />
|
||||
</a>
|
||||
</OverlayTrigger>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
)
|
||||
const loggedIn = web.LoggedIn()
|
||||
|
||||
if (loggedIn || prefixWritable) {
|
||||
return (
|
||||
<Dropdown dropup className="feb-actions" id="fe-action-toggle">
|
||||
<Dropdown.Toggle noCaret className="feba-toggle">
|
||||
<span>
|
||||
<i className="fa fa-plus" />
|
||||
</span>
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu>
|
||||
<OverlayTrigger placement="left" overlay={uploadTooltip}>
|
||||
<a href="#" className="feba-btn feba-upload">
|
||||
<input
|
||||
type="file"
|
||||
onChange={onFileUpload}
|
||||
style={{ display: "none" }}
|
||||
id="file-input"
|
||||
/>
|
||||
<label htmlFor="file-input">
|
||||
{" "}
|
||||
<i className="fa fa-cloud-upload" />{" "}
|
||||
</label>
|
||||
</a>
|
||||
</OverlayTrigger>
|
||||
{loggedIn && (
|
||||
<OverlayTrigger placement="left" overlay={makeBucketTooltip}>
|
||||
<a
|
||||
href="#"
|
||||
id="show-make-bucket"
|
||||
className="feba-btn feba-bucket"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
showMakeBucketModal()
|
||||
}}
|
||||
>
|
||||
<i className="fa fa-hdd-o" />
|
||||
</a>
|
||||
</OverlayTrigger>
|
||||
)}
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
)
|
||||
} else {
|
||||
return <noscript />
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => state
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
prefixWritable: getPrefixWritable(state)
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
|
@ -25,6 +25,7 @@ import BucketSearch from "../buckets/BucketSearch"
|
||||
import BucketList from "../buckets/BucketList"
|
||||
import Host from "./Host"
|
||||
import * as actionsCommon from "./actions"
|
||||
import web from "../web"
|
||||
|
||||
export const SideBar = ({ sidebarOpen, clickOutside }) => {
|
||||
return (
|
||||
@ -40,7 +41,7 @@ export const SideBar = ({ sidebarOpen, clickOutside }) => {
|
||||
<h2>Minio Browser</h2>
|
||||
</div>
|
||||
<div className="fes-list">
|
||||
<BucketSearch />
|
||||
{web.LoggedIn() && <BucketSearch />}
|
||||
<BucketList />
|
||||
</div>
|
||||
<Host />
|
||||
|
@ -18,11 +18,37 @@ import React from "react"
|
||||
import { shallow, mount } from "enzyme"
|
||||
import { MainActions } from "../MainActions"
|
||||
|
||||
jest.mock("../../web", () => ({
|
||||
LoggedIn: jest
|
||||
.fn(() => true)
|
||||
.mockReturnValueOnce(true)
|
||||
.mockReturnValueOnce(false)
|
||||
.mockReturnValueOnce(false)
|
||||
}))
|
||||
|
||||
describe("MainActions", () => {
|
||||
it("should render without crashing", () => {
|
||||
shallow(<MainActions />)
|
||||
})
|
||||
|
||||
it("should not show any actions when user has not LoggedIn and prefixWritable is false", () => {
|
||||
const wrapper = shallow(<MainActions />)
|
||||
expect(wrapper.find("#show-make-bucket").length).toBe(0)
|
||||
expect(wrapper.find("#file-input").length).toBe(0)
|
||||
})
|
||||
|
||||
it("should show only file upload action when user has not LoggedIn and prefixWritable is true", () => {
|
||||
const wrapper = shallow(<MainActions prefixWritable={true} />)
|
||||
expect(wrapper.find("#show-make-bucket").length).toBe(0)
|
||||
expect(wrapper.find("#file-input").length).toBe(1)
|
||||
})
|
||||
|
||||
it("should show make bucket upload file actions when user has LoggedIn", () => {
|
||||
const wrapper = shallow(<MainActions />)
|
||||
expect(wrapper.find("#show-make-bucket").length).toBe(1)
|
||||
expect(wrapper.find("#file-input").length).toBe(1)
|
||||
})
|
||||
|
||||
it("should call showMakeBucketModal when create bucket icon is clicked", () => {
|
||||
const showMakeBucketModal = jest.fn()
|
||||
const wrapper = shallow(
|
||||
|
@ -18,11 +18,20 @@ import React from "react"
|
||||
import { shallow } from "enzyme"
|
||||
import { SideBar } from "../SideBar"
|
||||
|
||||
jest.mock("../../web", () => ({
|
||||
LoggedIn: jest.fn(() => false).mockReturnValueOnce(true)
|
||||
}))
|
||||
|
||||
describe("SideBar", () => {
|
||||
it("should render without crashing", () => {
|
||||
shallow(<SideBar />)
|
||||
})
|
||||
|
||||
it("should not render BucketSearch for non LoggedIn users", () => {
|
||||
const wrapper = shallow(<SideBar />)
|
||||
expect(wrapper.find("Connect(BucketSearch)").length).toBe(0)
|
||||
})
|
||||
|
||||
it("should call clickOutside when the user clicks outside the sidebar", () => {
|
||||
const clickOutside = jest.fn()
|
||||
const wrapper = shallow(<SideBar clickOutside={clickOutside} />)
|
||||
|
@ -20,11 +20,22 @@ import { Scrollbars } from "react-custom-scrollbars"
|
||||
import * as actionsBuckets from "./actions"
|
||||
import { getVisibleBuckets } from "./selectors"
|
||||
import BucketContainer from "./BucketContainer"
|
||||
import web from "../web"
|
||||
import history from "../history"
|
||||
import { pathSlice } from "../utils"
|
||||
|
||||
export class BucketList extends React.Component {
|
||||
componentWillMount() {
|
||||
const { fetchBuckets } = this.props
|
||||
fetchBuckets()
|
||||
const { fetchBuckets, setBucketList, selectBucket } = this.props
|
||||
if (web.LoggedIn()) {
|
||||
fetchBuckets()
|
||||
} else {
|
||||
const { bucket, prefix } = pathSlice(history.location.pathname)
|
||||
if (bucket) {
|
||||
setBucketList([bucket])
|
||||
selectBucket(bucket, prefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const { visibleBuckets } = this.props
|
||||
@ -52,7 +63,9 @@ const mapStateToProps = state => {
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
fetchBuckets: () => dispatch(actionsBuckets.fetchBuckets())
|
||||
fetchBuckets: () => dispatch(actionsBuckets.fetchBuckets()),
|
||||
setBucketList: buckets => dispatch(actionsBuckets.setList(buckets)),
|
||||
selectBucket: bucket => dispatch(actionsBuckets.selectBucket(bucket))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,16 @@
|
||||
|
||||
import React from "react"
|
||||
import { shallow } from "enzyme"
|
||||
import history from "../../history"
|
||||
import { BucketList } from "../BucketList"
|
||||
|
||||
jest.mock("../../web", () => ({
|
||||
LoggedIn: jest
|
||||
.fn(() => false)
|
||||
.mockReturnValueOnce(true)
|
||||
.mockReturnValueOnce(true)
|
||||
}))
|
||||
|
||||
describe("BucketList", () => {
|
||||
it("should render without crashing", () => {
|
||||
const fetchBuckets = jest.fn()
|
||||
@ -31,4 +39,19 @@ describe("BucketList", () => {
|
||||
)
|
||||
expect(fetchBuckets).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should call setBucketList and selectBucket before component is mounted when the user has not loggedIn", () => {
|
||||
const setBucketList = jest.fn()
|
||||
const selectBucket = jest.fn()
|
||||
history.push("/bk1/pre1")
|
||||
const wrapper = shallow(
|
||||
<BucketList
|
||||
visibleBuckets={[]}
|
||||
setBucketList={setBucketList}
|
||||
selectBucket={selectBucket}
|
||||
/>
|
||||
)
|
||||
expect(setBucketList).toHaveBeenCalledWith(["bk1"])
|
||||
expect(selectBucket).toHaveBeenCalledWith("bk1", "pre1")
|
||||
})
|
||||
})
|
||||
|
@ -18,6 +18,7 @@ import configureStore from "redux-mock-store"
|
||||
import thunk from "redux-thunk"
|
||||
import * as actionsBuckets from "../actions"
|
||||
import * as objectActions from "../../objects/actions"
|
||||
import history from "../../history"
|
||||
|
||||
jest.mock("../../web", () => ({
|
||||
ListBuckets: jest.fn(() => {
|
||||
@ -36,7 +37,7 @@ const middlewares = [thunk]
|
||||
const mockStore = configureStore(middlewares)
|
||||
|
||||
describe("Buckets actions", () => {
|
||||
it("creates buckets/SET_LIST and buckets/SET_CURRENT_BUCKET after fetching the buckets", () => {
|
||||
it("creates buckets/SET_LIST and buckets/SET_CURRENT_BUCKET with first bucket after fetching the buckets", () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: "buckets/SET_LIST", buckets: ["test1", "test2"] },
|
||||
@ -48,7 +49,35 @@ describe("Buckets actions", () => {
|
||||
})
|
||||
})
|
||||
|
||||
it("should update browser url and creates buckets/SET_CURRENT_BUCKET action when selectBucket is called", () => {
|
||||
it("creates buckets/SET_CURRENT_BUCKET with bucket name in the url after fetching buckets", () => {
|
||||
history.push("/test2")
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: "buckets/SET_LIST", buckets: ["test1", "test2"] },
|
||||
{ type: "buckets/SET_CURRENT_BUCKET", bucket: "test2" }
|
||||
]
|
||||
window.location
|
||||
return store.dispatch(actionsBuckets.fetchBuckets()).then(() => {
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
})
|
||||
})
|
||||
|
||||
it("creates buckets/SET_CURRENT_BUCKET with first bucket when the bucket in url is not exists after fetching buckets", () => {
|
||||
history.push("/test3")
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: "buckets/SET_LIST", buckets: ["test1", "test2"] },
|
||||
{ type: "buckets/SET_CURRENT_BUCKET", bucket: "test1" }
|
||||
]
|
||||
window.location
|
||||
return store.dispatch(actionsBuckets.fetchBuckets()).then(() => {
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
})
|
||||
})
|
||||
|
||||
it("creates buckets/SET_CURRENT_BUCKET action when selectBucket is called", () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: "buckets/SET_CURRENT_BUCKET", bucket: "test1" }
|
||||
@ -56,7 +85,6 @@ describe("Buckets actions", () => {
|
||||
store.dispatch(actionsBuckets.selectBucket("test1"))
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
expect(window.location.pathname).toBe("/test1")
|
||||
})
|
||||
|
||||
it("creates buckets/SHOW_MAKE_BUCKET_MODAL for showMakeBucketModal", () => {
|
||||
|
@ -18,6 +18,7 @@ import web from "../web"
|
||||
import history from "../history"
|
||||
import * as alertActions from "../alert/actions"
|
||||
import * as objectsActions from "../objects/actions"
|
||||
import { pathSlice } from "../utils"
|
||||
|
||||
export const SET_LIST = "buckets/SET_LIST"
|
||||
export const ADD = "buckets/ADD"
|
||||
@ -31,7 +32,12 @@ export const fetchBuckets = () => {
|
||||
const buckets = res.buckets ? res.buckets.map(bucket => bucket.name) : []
|
||||
dispatch(setList(buckets))
|
||||
if (buckets.length > 0) {
|
||||
dispatch(selectBucket(buckets[0]))
|
||||
const { bucket, prefix } = pathSlice(history.location.pathname)
|
||||
if (bucket && buckets.indexOf(bucket) > -1) {
|
||||
dispatch(selectBucket(bucket, prefix))
|
||||
} else {
|
||||
dispatch(selectBucket(buckets[0]))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -51,11 +57,10 @@ export const setFilter = filter => {
|
||||
}
|
||||
}
|
||||
|
||||
export const selectBucket = bucket => {
|
||||
export const selectBucket = (bucket, prefix) => {
|
||||
return function(dispatch) {
|
||||
dispatch(setCurrentBucket(bucket))
|
||||
dispatch(objectsActions.selectPrefix(""))
|
||||
history.push(`/${bucket}`)
|
||||
dispatch(objectsActions.selectPrefix(prefix || ""))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,8 @@ jest.mock("../../web", () => ({
|
||||
return Promise.resolve({
|
||||
objects: [{ name: "test1" }, { name: "test2" }],
|
||||
istruncated: false,
|
||||
nextmarker: "test2"
|
||||
nextmarker: "test2",
|
||||
writable: false
|
||||
})
|
||||
}),
|
||||
RemoveObject: jest.fn(({ bucketName, objects }) => {
|
||||
@ -124,6 +125,10 @@ describe("Objects actions", () => {
|
||||
{
|
||||
type: "objects/SET_SORT_ORDER",
|
||||
sortOrder: false
|
||||
},
|
||||
{
|
||||
type: "objects/SET_PREFIX_WRITABLE",
|
||||
prefixWritable: false
|
||||
}
|
||||
]
|
||||
return store.dispatch(actionsObjects.fetchObjects()).then(() => {
|
||||
@ -143,6 +148,10 @@ describe("Objects actions", () => {
|
||||
objects: [{ name: "test1" }, { name: "test2" }],
|
||||
marker: "test2",
|
||||
isTruncated: false
|
||||
},
|
||||
{
|
||||
type: "objects/SET_PREFIX_WRITABLE",
|
||||
prefixWritable: false
|
||||
}
|
||||
]
|
||||
return store.dispatch(actionsObjects.fetchObjects(true)).then(() => {
|
||||
@ -197,6 +206,16 @@ describe("Objects actions", () => {
|
||||
expect(window.location.pathname.endsWith("/test/abc/")).toBeTruthy()
|
||||
})
|
||||
|
||||
it("create objects/SET_PREFIX_WRITABLE action", () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: "objects/SET_PREFIX_WRITABLE", prefixWritable: true }
|
||||
]
|
||||
store.dispatch(actionsObjects.setPrefixWritable(true))
|
||||
const actions = store.getActions()
|
||||
expect(actions).toEqual(expectedActions)
|
||||
})
|
||||
|
||||
it("creates objects/REMOVE action", () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [{ type: "objects/REMOVE", object: "obj1" }]
|
||||
|
@ -27,6 +27,7 @@ describe("objects reducer", () => {
|
||||
currentPrefix: "",
|
||||
marker: "",
|
||||
isTruncated: false,
|
||||
prefixWritable: false,
|
||||
shareObject: {
|
||||
show: false,
|
||||
object: "",
|
||||
@ -123,6 +124,14 @@ describe("objects reducer", () => {
|
||||
expect(newState.isTruncated).toBeFalsy()
|
||||
})
|
||||
|
||||
it("should handle SET_PREFIX_WRITABLE", () => {
|
||||
const newState = reducer(undefined, {
|
||||
type: actions.SET_PREFIX_WRITABLE,
|
||||
prefixWritable: true
|
||||
})
|
||||
expect(newState.prefixWritable).toBeTruthy()
|
||||
})
|
||||
|
||||
it("should handle SET_SHARE_OBJECT", () => {
|
||||
const newState = reducer(undefined, {
|
||||
type: actions.SET_SHARE_OBJECT,
|
||||
|
@ -32,6 +32,7 @@ export const REMOVE = "objects/REMOVE"
|
||||
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 SET_PREFIX_WRITABLE = "objects/SET_PREFIX_WRITABLE"
|
||||
export const SET_SHARE_OBJECT = "objects/SET_SHARE_OBJECT"
|
||||
export const CHECKED_LIST_ADD = "objects/CHECKED_LIST_ADD"
|
||||
export const CHECKED_LIST_REMOVE = "objects/CHECKED_LIST_REMOVE"
|
||||
@ -80,6 +81,11 @@ export const fetchObjects = append => {
|
||||
dispatch(setSortBy(""))
|
||||
dispatch(setSortOrder(false))
|
||||
}
|
||||
dispatch(setPrefixWritable(res.writable))
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(alertActions.set({ type: "danger", message: err.message }))
|
||||
history.push("/login")
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -136,6 +142,11 @@ export const setCurrentPrefix = prefix => {
|
||||
}
|
||||
}
|
||||
|
||||
export const setPrefixWritable = prefixWritable => ({
|
||||
type: SET_PREFIX_WRITABLE,
|
||||
prefixWritable
|
||||
})
|
||||
|
||||
export const deleteObject = object => {
|
||||
return function(dispatch, getState) {
|
||||
const currentBucket = getCurrentBucket(getState())
|
||||
|
@ -32,6 +32,7 @@ export default (
|
||||
currentPrefix: "",
|
||||
marker: "",
|
||||
isTruncated: false,
|
||||
prefixWritable: false,
|
||||
shareObject: {
|
||||
show: false,
|
||||
object: "",
|
||||
@ -78,6 +79,11 @@ export default (
|
||||
marker: "",
|
||||
isTruncated: false
|
||||
}
|
||||
case actionsObjects.SET_PREFIX_WRITABLE:
|
||||
return {
|
||||
...state,
|
||||
prefixWritable: action.prefixWritable
|
||||
}
|
||||
case actionsObjects.SET_SHARE_OBJECT:
|
||||
return {
|
||||
...state,
|
||||
|
@ -19,3 +19,5 @@ import { createSelector } from "reselect"
|
||||
export const getCurrentPrefix = state => state.objects.currentPrefix
|
||||
|
||||
export const getCheckedList = state => state.objects.checkedList
|
||||
|
||||
export const getPrefixWritable = state => state.objects.prefixWritable
|
||||
|
Loading…
Reference in New Issue
Block a user