sortObjects("name")}
+ onClick={() => sortObjects(SORT_BY_NAME)}
data-sort="name"
>
Name
sortObjects("size")}
+ onClick={() => sortObjects(SORT_BY_SIZE)}
data-sort="size"
>
Size
sortObjects("last-modified")}
+ onClick={() => sortObjects(SORT_BY_LAST_MODIFIED)}
data-sort="last-modified"
>
Last Modified
@@ -83,10 +97,10 @@ export const ObjectsHeader = ({
const mapStateToProps = state => {
return {
- sortNameOrder: state.objects.sortBy == "name" && state.objects.sortOrder,
- sortSizeOrder: state.objects.sortBy == "size" && state.objects.sortOrder,
- sortLastModifiedOrder:
- state.objects.sortBy == "last-modified" && state.objects.sortOrder
+ sortedByName: state.objects.sortBy == SORT_BY_NAME,
+ sortedBySize: state.objects.sortBy == SORT_BY_SIZE,
+ sortedByLastModified: state.objects.sortBy == SORT_BY_LAST_MODIFIED,
+ sortOrder: state.objects.sortOrder
}
}
@@ -96,4 +110,7 @@ const mapDispatchToProps = dispatch => {
}
}
-export default connect(mapStateToProps, mapDispatchToProps)(ObjectsHeader)
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(ObjectsHeader)
diff --git a/browser/app/js/objects/ObjectsListContainer.js b/browser/app/js/objects/ObjectsListContainer.js
index 7b4d11a81..2767980c3 100644
--- a/browser/app/js/objects/ObjectsListContainer.js
+++ b/browser/app/js/objects/ObjectsListContainer.js
@@ -15,32 +15,52 @@
*/
import React from "react"
-import classNames from "classnames"
import { connect } from "react-redux"
import InfiniteScroll from "react-infinite-scroller"
-import * as actionsObjects from "./actions"
import ObjectsList from "./ObjectsList"
export class ObjectsListContainer extends React.Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ page: 1
+ }
+ this.loadNextPage = this.loadNextPage.bind(this)
+ }
+ componentWillReceiveProps(nextProps) {
+ if (
+ nextProps.currentBucket !== this.props.currentBucket ||
+ nextProps.currentPrefix !== this.props.currentPrefix ||
+ nextProps.sortBy !== this.props.sortBy ||
+ nextProps.sortOrder !== this.props.sortOrder
+ ) {
+ this.setState({
+ page: 1
+ })
+ }
+ }
+ loadNextPage() {
+ this.setState(state => {
+ return { page: state.page + 1 }
+ })
+ }
render() {
- const { objects, isTruncated, currentBucket, loadObjects } = this.props
+ const { objects, listLoading } = this.props
+
+ const visibleObjects = objects.slice(0, this.state.page * 100)
+
return (
-
+
loadObjects(true)}
- hasMore={isTruncated}
+ loadMore={this.loadNextPage}
+ hasMore={objects.length > visibleObjects.length}
useWindow={true}
initialLoad={false}
>
-
+
-
- Loading...
-
+ {listLoading &&
}
)
}
@@ -51,16 +71,10 @@ const mapStateToProps = state => {
currentBucket: state.buckets.currentBucket,
currentPrefix: state.objects.currentPrefix,
objects: state.objects.list,
- isTruncated: state.objects.isTruncated
+ sortBy: state.objects.sortBy,
+ sortOrder: state.objects.sortOrder,
+ listLoading: state.objects.listLoading
}
}
-const mapDispatchToProps = dispatch => {
- return {
- loadObjects: append => dispatch(actionsObjects.fetchObjects(append))
- }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(
- ObjectsListContainer
-)
+export default connect(mapStateToProps)(ObjectsListContainer)
diff --git a/browser/app/js/objects/__tests__/ObjectsHeader.test.js b/browser/app/js/objects/__tests__/ObjectsHeader.test.js
index b7d079d99..ec49f5552 100644
--- a/browser/app/js/objects/__tests__/ObjectsHeader.test.js
+++ b/browser/app/js/objects/__tests__/ObjectsHeader.test.js
@@ -17,6 +17,7 @@
import React from "react"
import { shallow } from "enzyme"
import { ObjectsHeader } from "../ObjectsHeader"
+import { SORT_ORDER_ASC, SORT_ORDER_DESC } from "../../constants"
describe("ObjectsHeader", () => {
it("should render without crashing", () => {
@@ -24,44 +25,84 @@ describe("ObjectsHeader", () => {
shallow(
)
})
- it("should render columns with asc classes by default", () => {
+ it("should render the name column with asc class when objects are sorted by name asc", () => {
const sortObjects = jest.fn()
- const wrapper = shallow(
)
+ const wrapper = shallow(
+
+ )
expect(
wrapper.find("#sort-by-name i").hasClass("fa-sort-alpha-asc")
).toBeTruthy()
- expect(
- wrapper.find("#sort-by-size i").hasClass("fa-sort-amount-asc")
- ).toBeTruthy()
- expect(
- wrapper.find("#sort-by-last-modified i").hasClass("fa-sort-numeric-asc")
- ).toBeTruthy()
})
- it("should render name column with desc class when objects are sorted by name", () => {
+ it("should render the name column with desc class when objects are sorted by name desc", () => {
const sortObjects = jest.fn()
const wrapper = shallow(
-
+
)
expect(
wrapper.find("#sort-by-name i").hasClass("fa-sort-alpha-desc")
).toBeTruthy()
})
- it("should render size column with desc class when objects are sorted by size", () => {
+ it("should render the size column with asc class when objects are sorted by size asc", () => {
const sortObjects = jest.fn()
const wrapper = shallow(
-
+
+ )
+ expect(
+ wrapper.find("#sort-by-size i").hasClass("fa-sort-amount-asc")
+ ).toBeTruthy()
+ })
+
+ it("should render the size column with desc class when objects are sorted by size desc", () => {
+ const sortObjects = jest.fn()
+ const wrapper = shallow(
+
)
expect(
wrapper.find("#sort-by-size i").hasClass("fa-sort-amount-desc")
).toBeTruthy()
})
- it("should render last modified column with desc class when objects are sorted by last modified", () => {
+ it("should render the date column with asc class when objects are sorted by date asc", () => {
const sortObjects = jest.fn()
const wrapper = shallow(
-
+
+ )
+ expect(
+ wrapper.find("#sort-by-last-modified i").hasClass("fa-sort-numeric-asc")
+ ).toBeTruthy()
+ })
+
+ it("should render the date column with desc class when objects are sorted by date desc", () => {
+ const sortObjects = jest.fn()
+ const wrapper = shallow(
+
)
expect(
wrapper.find("#sort-by-last-modified i").hasClass("fa-sort-numeric-desc")
diff --git a/browser/app/js/objects/__tests__/ObjectsListContainer.test.js b/browser/app/js/objects/__tests__/ObjectsListContainer.test.js
index 805967ee6..3b25d36aa 100644
--- a/browser/app/js/objects/__tests__/ObjectsListContainer.test.js
+++ b/browser/app/js/objects/__tests__/ObjectsListContainer.test.js
@@ -20,14 +20,13 @@ import { ObjectsListContainer } from "../ObjectsListContainer"
describe("ObjectsList", () => {
it("should render without crashing", () => {
- shallow(
)
+ shallow(
)
})
it("should render ObjectsList with objects", () => {
const wrapper = shallow(
)
expect(wrapper.find("ObjectsList").length).toBe(1)
@@ -37,10 +36,14 @@ describe("ObjectsList", () => {
])
})
- it("should show the loading indicator at the bottom if there are more elements to display", () => {
+ it("should show the loading indicator when the objects are being loaded", () => {
const wrapper = shallow(
-
+
)
- expect(wrapper.find(".text-center").prop("style")).toHaveProperty("display", "block")
+ expect(wrapper.find(".loading").exists()).toBeTruthy()
})
})
diff --git a/browser/app/js/objects/__tests__/actions.test.js b/browser/app/js/objects/__tests__/actions.test.js
index 1ee2d8f98..a769f5fc2 100644
--- a/browser/app/js/objects/__tests__/actions.test.js
+++ b/browser/app/js/objects/__tests__/actions.test.js
@@ -18,7 +18,13 @@ import configureStore from "redux-mock-store"
import thunk from "redux-thunk"
import * as actionsObjects from "../actions"
import * as alertActions from "../../alert/actions"
-import { minioBrowserPrefix } from "../../constants"
+import {
+ minioBrowserPrefix,
+ SORT_BY_NAME,
+ SORT_ORDER_ASC,
+ SORT_BY_LAST_MODIFIED,
+ SORT_ORDER_DESC
+} from "../../constants"
import history from "../../history"
jest.mock("../../web", () => ({
@@ -37,8 +43,6 @@ jest.mock("../../web", () => ({
} else {
return Promise.resolve({
objects: [{ name: "test1" }, { name: "test2" }],
- istruncated: false,
- nextmarker: "test2",
writable: false
})
}
@@ -77,17 +81,11 @@ describe("Objects actions", () => {
const expectedActions = [
{
type: "objects/SET_LIST",
- objects: [{ name: "test1" }, { name: "test2" }],
- isTruncated: false,
- marker: "test2"
+ objects: [{ name: "test1" }, { name: "test2" }]
}
]
store.dispatch(
- actionsObjects.setList(
- [{ name: "test1" }, { name: "test2" }],
- "test2",
- false
- )
+ actionsObjects.setList([{ name: "test1" }, { name: "test2" }])
)
const actions = store.getActions()
expect(actions).toEqual(expectedActions)
@@ -98,10 +96,10 @@ describe("Objects actions", () => {
const expectedActions = [
{
type: "objects/SET_SORT_BY",
- sortBy: "name"
+ sortBy: SORT_BY_NAME
}
]
- store.dispatch(actionsObjects.setSortBy("name"))
+ store.dispatch(actionsObjects.setSortBy(SORT_BY_NAME))
const actions = store.getActions()
expect(actions).toEqual(expectedActions)
})
@@ -111,10 +109,10 @@ describe("Objects actions", () => {
const expectedActions = [
{
type: "objects/SET_SORT_ORDER",
- sortOrder: true
+ sortOrder: SORT_ORDER_ASC
}
]
- store.dispatch(actionsObjects.setSortOrder(true))
+ store.dispatch(actionsObjects.setSortOrder(SORT_ORDER_ASC))
const actions = store.getActions()
expect(actions).toEqual(expectedActions)
})
@@ -126,23 +124,26 @@ describe("Objects actions", () => {
})
const expectedActions = [
{
- type: "objects/SET_LIST",
- objects: [{ name: "test1" }, { name: "test2" }],
- marker: "test2",
- isTruncated: false
+ type: "objects/RESET_LIST"
},
+ { listLoading: true, type: "objects/SET_LIST_LOADING" },
{
type: "objects/SET_SORT_BY",
- sortBy: ""
+ sortBy: SORT_BY_LAST_MODIFIED
},
{
type: "objects/SET_SORT_ORDER",
- sortOrder: false
+ sortOrder: SORT_ORDER_DESC
+ },
+ {
+ type: "objects/SET_LIST",
+ objects: [{ name: "test2" }, { name: "test1" }]
},
{
type: "objects/SET_PREFIX_WRITABLE",
prefixWritable: false
- }
+ },
+ { listLoading: false, type: "objects/SET_LIST_LOADING" }
]
return store.dispatch(actionsObjects.fetchObjects()).then(() => {
const actions = store.getActions()
@@ -150,35 +151,16 @@ describe("Objects actions", () => {
})
})
- it("creates objects/APPEND_LIST after fetching more objects", () => {
- const store = mockStore({
- buckets: { currentBucket: "bk1" },
- objects: { currentPrefix: "" }
- })
- const expectedActions = [
- {
- type: "objects/APPEND_LIST",
- objects: [{ name: "test1" }, { name: "test2" }],
- marker: "test2",
- isTruncated: false
- },
- {
- type: "objects/SET_PREFIX_WRITABLE",
- prefixWritable: false
- }
- ]
- return store.dispatch(actionsObjects.fetchObjects(true)).then(() => {
- const actions = store.getActions()
- expect(actions).toEqual(expectedActions)
- })
- })
-
it("creates objects/RESET_LIST after failing to fetch the objects from bucket with ListObjects denied for LoggedIn users", () => {
const store = mockStore({
buckets: { currentBucket: "test-deny" },
objects: { currentPrefix: "" }
})
const expectedActions = [
+ {
+ type: "objects/RESET_LIST"
+ },
+ { listLoading: true, type: "objects/SET_LIST_LOADING" },
{
type: "alert/SET",
alert: {
@@ -189,8 +171,9 @@ describe("Objects actions", () => {
}
},
{
- type: "object/RESET_LIST"
- }
+ type: "objects/RESET_LIST"
+ },
+ { listLoading: false, type: "objects/SET_LIST_LOADING" }
]
return store.dispatch(actionsObjects.fetchObjects()).then(() => {
const actions = store.getActions()
@@ -213,28 +196,24 @@ describe("Objects actions", () => {
objects: {
list: [],
sortBy: "",
- sortOrder: false,
- isTruncated: false,
- marker: ""
+ sortOrder: SORT_ORDER_ASC
}
})
const expectedActions = [
{
type: "objects/SET_SORT_BY",
- sortBy: "name"
+ sortBy: SORT_BY_NAME
},
{
type: "objects/SET_SORT_ORDER",
- sortOrder: true
+ sortOrder: SORT_ORDER_ASC
},
{
type: "objects/SET_LIST",
- objects: [],
- isTruncated: false,
- marker: ""
+ objects: []
}
]
- store.dispatch(actionsObjects.sortObjects("name"))
+ store.dispatch(actionsObjects.sortObjects(SORT_BY_NAME))
const actions = store.getActions()
expect(actions).toEqual(expectedActions)
})
@@ -246,6 +225,10 @@ describe("Objects actions", () => {
})
const expectedActions = [
{ type: "objects/SET_CURRENT_PREFIX", prefix: "abc/" },
+ {
+ type: "objects/RESET_LIST"
+ },
+ { listLoading: true, type: "objects/SET_LIST_LOADING" },
{ type: "objects/CHECKED_LIST_RESET" }
]
store.dispatch(actionsObjects.selectPrefix("abc/"))
diff --git a/browser/app/js/objects/__tests__/reducer.test.js b/browser/app/js/objects/__tests__/reducer.test.js
index 1a0de01d8..635143cbb 100644
--- a/browser/app/js/objects/__tests__/reducer.test.js
+++ b/browser/app/js/objects/__tests__/reducer.test.js
@@ -16,17 +16,17 @@
import reducer from "../reducer"
import * as actions from "../actions"
+import { SORT_ORDER_ASC, SORT_BY_NAME } from "../../constants"
describe("objects reducer", () => {
it("should return the initial state", () => {
const initialState = reducer(undefined, {})
expect(initialState).toEqual({
list: [],
+ listLoading: false,
sortBy: "",
- sortOrder: false,
+ sortOrder: SORT_ORDER_ASC,
currentPrefix: "",
- marker: "",
- isTruncated: false,
prefixWritable: false,
shareObject: {
show: false,
@@ -40,37 +40,9 @@ describe("objects reducer", () => {
it("should handle SET_LIST", () => {
const newState = reducer(undefined, {
type: actions.SET_LIST,
- objects: [{ name: "obj1" }, { name: "obj2" }],
- marker: "obj2",
- isTruncated: false
+ objects: [{ name: "obj1" }, { name: "obj2" }]
})
expect(newState.list).toEqual([{ name: "obj1" }, { name: "obj2" }])
- expect(newState.marker).toBe("obj2")
- expect(newState.isTruncated).toBeFalsy()
- })
-
- it("should handle APPEND_LIST", () => {
- const newState = reducer(
- {
- list: [{ name: "obj1" }, { name: "obj2" }],
- marker: "obj2",
- isTruncated: true
- },
- {
- type: actions.APPEND_LIST,
- objects: [{ name: "obj3" }, { name: "obj4" }],
- marker: "obj4",
- isTruncated: false
- }
- )
- expect(newState.list).toEqual([
- { name: "obj1" },
- { name: "obj2" },
- { name: "obj3" },
- { name: "obj4" }
- ])
- expect(newState.marker).toBe("obj4")
- expect(newState.isTruncated).toBeFalsy()
})
it("should handle REMOVE", () => {
@@ -98,30 +70,28 @@ describe("objects reducer", () => {
it("should handle SET_SORT_BY", () => {
const newState = reducer(undefined, {
type: actions.SET_SORT_BY,
- sortBy: "name"
+ sortBy: SORT_BY_NAME
})
- expect(newState.sortBy).toEqual("name")
+ expect(newState.sortBy).toEqual(SORT_BY_NAME)
})
it("should handle SET_SORT_ORDER", () => {
const newState = reducer(undefined, {
type: actions.SET_SORT_ORDER,
- sortOrder: true
+ sortOrder: SORT_ORDER_ASC
})
- expect(newState.sortOrder).toEqual(true)
+ expect(newState.sortOrder).toEqual(SORT_ORDER_ASC)
})
it("should handle SET_CURRENT_PREFIX", () => {
const newState = reducer(
- { currentPrefix: "test1/", marker: "abc", isTruncated: true },
+ { currentPrefix: "test1/" },
{
type: actions.SET_CURRENT_PREFIX,
prefix: "test2/"
}
)
expect(newState.currentPrefix).toEqual("test2/")
- expect(newState.marker).toEqual("")
- expect(newState.isTruncated).toBeFalsy()
})
it("should handle SET_PREFIX_WRITABLE", () => {
diff --git a/browser/app/js/objects/actions.js b/browser/app/js/objects/actions.js
index 59c5af863..9bb73d04c 100644
--- a/browser/app/js/objects/actions.js
+++ b/browser/app/js/objects/actions.js
@@ -16,15 +16,26 @@
import web from "../web"
import history from "../history"
-import { sortObjectsByName, sortObjectsBySize, sortObjectsByDate } from "../utils"
+import {
+ sortObjectsByName,
+ sortObjectsBySize,
+ sortObjectsByDate
+} from "../utils"
import { getCurrentBucket } from "../buckets/selectors"
import { getCurrentPrefix, getCheckedList } from "./selectors"
import * as alertActions from "../alert/actions"
import * as bucketActions from "../buckets/actions"
-import { minioBrowserPrefix } from "../constants"
+import {
+ minioBrowserPrefix,
+ SORT_BY_NAME,
+ SORT_BY_SIZE,
+ SORT_BY_LAST_MODIFIED,
+ SORT_ORDER_ASC,
+ SORT_ORDER_DESC
+} from "../constants"
export const SET_LIST = "objects/SET_LIST"
-export const RESET_LIST = "object/RESET_LIST"
+export const RESET_LIST = "objects/RESET_LIST"
export const APPEND_LIST = "objects/APPEND_LIST"
export const REMOVE = "objects/REMOVE"
export const SET_SORT_BY = "objects/SET_SORT_BY"
@@ -35,34 +46,35 @@ 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"
export const CHECKED_LIST_RESET = "objects/CHECKED_LIST_RESET"
+export const SET_LIST_LOADING = "objects/SET_LIST_LOADING"
-export const setList = (objects, marker, isTruncated) => ({
+export const setList = objects => ({
type: SET_LIST,
- objects,
- marker,
- isTruncated
+ objects
})
export const resetList = () => ({
type: RESET_LIST
})
-export const appendList = (objects, marker, isTruncated) => ({
- type: APPEND_LIST,
- objects,
- marker,
- isTruncated
+export const setListLoading = listLoading => ({
+ type: SET_LIST_LOADING,
+ listLoading
})
-export const fetchObjects = append => {
+export const fetchObjects = () => {
return function(dispatch, getState) {
- const {buckets: {currentBucket}, objects: {currentPrefix, marker}} = getState()
+ dispatch(resetList())
+ const {
+ buckets: { currentBucket },
+ objects: { currentPrefix }
+ } = getState()
if (currentBucket) {
+ dispatch(setListLoading(true))
return web
.ListObjects({
bucketName: currentBucket,
- prefix: currentPrefix,
- marker: append ? marker : ""
+ prefix: currentPrefix
})
.then(res => {
let objects = []
@@ -74,14 +86,16 @@ export const fetchObjects = append => {
}
})
}
- if (append) {
- dispatch(appendList(objects, res.nextmarker, res.istruncated))
- } else {
- dispatch(setList(objects, res.nextmarker, res.istruncated))
- dispatch(setSortBy(""))
- dispatch(setSortOrder(false))
- }
+
+ const sortBy = SORT_BY_LAST_MODIFIED
+ const sortOrder = SORT_ORDER_DESC
+ dispatch(setSortBy(sortBy))
+ dispatch(setSortOrder(sortOrder))
+ const sortedList = sortObjectsList(objects, sortBy, sortOrder)
+ dispatch(setList(sortedList))
+
dispatch(setPrefixWritable(res.writable))
+ dispatch(setListLoading(false))
})
.catch(err => {
if (web.LoggedIn()) {
@@ -96,6 +110,7 @@ export const fetchObjects = append => {
} else {
history.push("/login")
}
+ dispatch(setListLoading(false))
})
}
}
@@ -103,26 +118,27 @@ export const fetchObjects = append => {
export const sortObjects = sortBy => {
return function(dispatch, getState) {
- const {objects} = getState()
- const sortOrder = objects.sortBy == sortBy ? !objects.sortOrder : true
+ const { objects } = getState()
+ let sortOrder = SORT_ORDER_ASC
+ // Reverse sort order if the list is already sorted on same field
+ if (objects.sortBy === sortBy && objects.sortOrder === SORT_ORDER_ASC) {
+ sortOrder = SORT_ORDER_DESC
+ }
dispatch(setSortBy(sortBy))
dispatch(setSortOrder(sortOrder))
- let list
- switch (sortBy) {
- case "name":
- list = sortObjectsByName(objects.list, sortOrder)
- break
- case "size":
- list = sortObjectsBySize(objects.list, sortOrder)
- break
- case "last-modified":
- list = sortObjectsByDate(objects.list, sortOrder)
- break
- default:
- list = objects.list
- break
- }
- dispatch(setList(list, objects.marker, objects.isTruncated))
+ const sortedList = sortObjectsList(objects.list, sortBy, sortOrder)
+ dispatch(setList(sortedList))
+ }
+}
+
+const sortObjectsList = (list, sortBy, sortOrder) => {
+ switch (sortBy) {
+ case SORT_BY_NAME:
+ return sortObjectsByName(list, sortOrder)
+ case SORT_BY_SIZE:
+ return sortObjectsBySize(list, sortOrder)
+ case SORT_BY_LAST_MODIFIED:
+ return sortObjectsByDate(list, sortOrder)
}
}
@@ -229,7 +245,16 @@ export const shareObject = (object, days, hours, minutes) => {
)
})
} else {
- dispatch(showShareObject(object, `${location.host}` + '/' + `${currentBucket}` + '/' + encodeURI(objectName)))
+ dispatch(
+ showShareObject(
+ object,
+ `${location.host}` +
+ "/" +
+ `${currentBucket}` +
+ "/" +
+ encodeURI(objectName)
+ )
+ )
dispatch(
alertActions.set({
type: "success",
@@ -322,13 +347,14 @@ export const downloadCheckedObjects = () => {
}${minioBrowserPrefix}/zip?token=${res.token}`
downloadZip(requestUrl, req, dispatch)
})
- .catch(err => dispatch(
- alertActions.set({
- type: "danger",
- message: err.message
- })
+ .catch(err =>
+ dispatch(
+ alertActions.set({
+ type: "danger",
+ message: err.message
+ })
+ )
)
- )
}
}
}
@@ -351,7 +377,8 @@ const downloadZip = (url, req, dispatch) => {
var separator = req.prefix.length > 1 ? "-" : ""
anchor.href = blobUrl
- anchor.download = req.bucketName + separator + req.prefix.slice(0, -1) + ".zip"
+ anchor.download =
+ req.bucketName + separator + req.prefix.slice(0, -1) + ".zip"
anchor.click()
window.URL.revokeObjectURL(blobUrl)
diff --git a/browser/app/js/objects/reducer.js b/browser/app/js/objects/reducer.js
index 0357f99eb..801039c4e 100644
--- a/browser/app/js/objects/reducer.js
+++ b/browser/app/js/objects/reducer.js
@@ -15,6 +15,7 @@
*/
import * as actionsObjects from "./actions"
+import { SORT_ORDER_ASC } from "../constants"
const removeObject = (list, objectToRemove, lookup) => {
const idx = list.findIndex(object => lookup(object) === objectToRemove)
@@ -27,11 +28,10 @@ const removeObject = (list, objectToRemove, lookup) => {
export default (
state = {
list: [],
+ listLoading: false,
sortBy: "",
- sortOrder: false,
+ sortOrder: SORT_ORDER_ASC,
currentPrefix: "",
- marker: "",
- isTruncated: false,
prefixWritable: false,
shareObject: {
show: false,
@@ -46,23 +46,17 @@ export default (
case actionsObjects.SET_LIST:
return {
...state,
- list: action.objects,
- marker: action.marker,
- isTruncated: action.isTruncated
+ list: action.objects
}
case actionsObjects.RESET_LIST:
return {
...state,
- list: [],
- marker: "",
- isTruncated: false
+ list: []
}
- case actionsObjects.APPEND_LIST:
+ case actionsObjects.SET_LIST_LOADING:
return {
...state,
- list: [...state.list, ...action.objects],
- marker: action.marker,
- isTruncated: action.isTruncated
+ listLoading: action.listLoading
}
case actionsObjects.REMOVE:
return {
@@ -82,9 +76,7 @@ export default (
case actionsObjects.SET_CURRENT_PREFIX:
return {
...state,
- currentPrefix: action.prefix,
- marker: "",
- isTruncated: false
+ currentPrefix: action.prefix
}
case actionsObjects.SET_PREFIX_WRITABLE:
return {
diff --git a/browser/app/js/utils.js b/browser/app/js/utils.js
index 9e08da109..bbf19aa6a 100644
--- a/browser/app/js/utils.js
+++ b/browser/app/js/utils.js
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import { minioBrowserPrefix } from "./constants.js"
+import { minioBrowserPrefix, SORT_ORDER_DESC } from "./constants.js"
export const sortObjectsByName = (objects, order) => {
let folders = objects.filter(object => object.name.endsWith("/"))
@@ -29,7 +29,7 @@ export const sortObjectsByName = (objects, order) => {
if (a.name.toLowerCase() > b.name.toLowerCase()) return 1
return 0
})
- if (order) {
+ if (order === SORT_ORDER_DESC) {
folders = folders.reverse()
files = files.reverse()
}
@@ -40,7 +40,7 @@ export const sortObjectsBySize = (objects, order) => {
let folders = objects.filter(object => object.name.endsWith("/"))
let files = objects.filter(object => !object.name.endsWith("/"))
files = files.sort((a, b) => a.size - b.size)
- if (order) files = files.reverse()
+ if (order === SORT_ORDER_DESC) files = files.reverse()
return [...folders, ...files]
}
@@ -51,7 +51,7 @@ export const sortObjectsByDate = (objects, order) => {
(a, b) =>
new Date(a.lastModified).getTime() - new Date(b.lastModified).getTime()
)
- if (order) files = files.reverse()
+ if (order === SORT_ORDER_DESC) files = files.reverse()
return [...folders, ...files]
}
diff --git a/browser/app/less/inc/list.less b/browser/app/less/inc/list.less
index 7371539e3..f3d7ebe2c 100644
--- a/browser/app/less/inc/list.less
+++ b/browser/app/less/inc/list.less
@@ -43,6 +43,9 @@ header.fesl-row {
color: @dark-gray;
font-size: 14px;
}
+ & > .fesli-sort--active {
+ .opacity(0.5);
+ }
&:hover:not(.fesl-item-actions) {
background: lighten(@text-muted-color, 22%);
diff --git a/browser/app/less/inc/misc.less b/browser/app/less/inc/misc.less
index 8359d426d..28e00c8e6 100644
--- a/browser/app/less/inc/misc.less
+++ b/browser/app/less/inc/misc.less
@@ -113,4 +113,41 @@
margin: 0;
vertical-align: top;
}
+}
+
+.loading {
+ position: absolute;
+ margin: auto;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ border-top: 1px solid @loading-track-bg;
+ border-right: 1px solid @loading-track-bg;
+ border-bottom: 1px solid @loading-track-bg;
+ border-left: 1px solid @loading-point-bg;
+ transform: translateZ(0);
+ animation: loading 1.1s infinite linear;
+ border-radius: 50%;
+ width: 35px;
+ height: 35px;
+ margin-top: 30px;
+}
+
+@-webkit-keyframes loading {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+
+@keyframes loading {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
}
\ No newline at end of file
diff --git a/browser/app/less/inc/variables.less b/browser/app/less/inc/variables.less
index 9089fb2f2..173ef91a2 100644
--- a/browser/app/less/inc/variables.less
+++ b/browser/app/less/inc/variables.less
@@ -100,4 +100,10 @@
List
--------------------------*/
@list-row-selected-bg: #fbf2bf;
-@list-row-even-bg: #fafafa;
\ No newline at end of file
+@list-row-even-bg: #fafafa;
+
+/*--------------------------
+ Loading
+---------------------------*/
+@loading-track-bg: #eeeeee;
+@loading-point-bg: #00303f;
\ No newline at end of file
diff --git a/browser/ui-assets.go b/browser/ui-assets.go
index e7f8c84c1..3061e2c76 100644
--- a/browser/ui-assets.go
+++ b/browser/ui-assets.go
@@ -1,4 +1,4 @@
-// Package browser Code generated by go-bindata. (@generated) DO NOT EDIT.
+// Code generated by go-bindata.
// sources:
// production/chrome.png
// production/favicon-16x16.png
@@ -6,14 +6,17 @@
// production/favicon-96x96.png
// production/firefox.png
// production/index.html
-// production/index_bundle-2019-06-09T23-47-20Z.js
+// production/index_bundle-2019-06-19T09-39-21Z.js
// production/loader.css
// production/logo.svg
// production/safari.png
+// DO NOT EDIT!
+
package browser
import (
"fmt"
+ "github.com/elazarl/go-bindata-assetfs"
"io/ioutil"
"os"
"path/filepath"
@@ -33,32 +36,21 @@ type bindataFileInfo struct {
modTime time.Time
}
-// Name return file name
func (fi bindataFileInfo) Name() string {
return fi.name
}
-
-// Size return file size
func (fi bindataFileInfo) Size() int64 {
return fi.size
}
-
-// Mode return file mode
func (fi bindataFileInfo) Mode() os.FileMode {
return fi.mode
}
-
-// Mode return file modify time
func (fi bindataFileInfo) ModTime() time.Time {
return fi.modTime
}
-
-// IsDir return file whether a directory
func (fi bindataFileInfo) IsDir() bool {
- return fi.mode&os.ModeDir != 0
+ return false
}
-
-// Sys return file is sys mode
func (fi bindataFileInfo) Sys() interface{} {
return nil
}
@@ -75,7 +67,7 @@ func productionChromePng() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "production/chrome.png", size: 3726, mode: os.FileMode(420), modTime: time.Unix(1560124049, 0)}
+ info := bindataFileInfo{name: "production/chrome.png", size: 3726, mode: os.FileMode(420), modTime: time.Unix(1560937181, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -92,7 +84,7 @@ func productionFavicon16x16Png() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "production/favicon-16x16.png", size: 14906, mode: os.FileMode(420), modTime: time.Unix(1560124049, 0)}
+ info := bindataFileInfo{name: "production/favicon-16x16.png", size: 14906, mode: os.FileMode(420), modTime: time.Unix(1560937181, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -109,7 +101,7 @@ func productionFavicon32x32Png() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "production/favicon-32x32.png", size: 16066, mode: os.FileMode(420), modTime: time.Unix(1560124049, 0)}
+ info := bindataFileInfo{name: "production/favicon-32x32.png", size: 16066, mode: os.FileMode(420), modTime: time.Unix(1560937181, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -126,7 +118,7 @@ func productionFavicon96x96Png() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "production/favicon-96x96.png", size: 17029, mode: os.FileMode(420), modTime: time.Unix(1560124049, 0)}
+ info := bindataFileInfo{name: "production/favicon-96x96.png", size: 17029, mode: os.FileMode(420), modTime: time.Unix(1560937181, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -143,7 +135,7 @@ func productionFirefoxPng() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "production/firefox.png", size: 4795, mode: os.FileMode(420), modTime: time.Unix(1560124049, 0)}
+ info := bindataFileInfo{name: "production/firefox.png", size: 4795, mode: os.FileMode(420), modTime: time.Unix(1560937181, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -203,8 +195,8 @@ var _productionIndexHTML = []byte(`