mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
Make directory path in the header editable (#8018)
This change will allow users to navigate to their desired locations, including buckets and directories that haven't been "created" yet Fixes #7883 Add tests Change tooltip wording Migrate to Font Awesome 5 to use path icon Fix sidebar not closing on mobile
This commit is contained in:
parent
bf8ec8ad73
commit
a48a034e5a
@ -23,7 +23,7 @@
|
||||
<!--[if lt IE 11]>
|
||||
<div class="ie-warning">
|
||||
<div class="iw-inner">
|
||||
<i class="iwi-icon fa fa-warning"></i>
|
||||
<i class="iwi-icon fas fa-exclamation-triangle"></i>
|
||||
|
||||
You are using Internet Explorer version 12.0 or lower. Due to security issues and lack of support for Web Standards it is highly recommended that you upgrade to a modern browser
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import "babel-polyfill"
|
||||
import "./less/main.less"
|
||||
import "font-awesome/css/font-awesome.css"
|
||||
import "@fortawesome/fontawesome-free/css/all.css"
|
||||
import "material-design-iconic-font/dist/css/material-design-iconic-font.min.css"
|
||||
|
||||
import React from "react"
|
||||
|
@ -84,32 +84,32 @@ export class BrowserDropdown extends React.Component {
|
||||
<li>
|
||||
<Dropdown pullRight id="top-right-menu">
|
||||
<Dropdown.Toggle noCaret>
|
||||
<i className="fa fa-reorder" />
|
||||
<i className="fas fa-bars" />
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu className="dropdown-menu-right">
|
||||
<li>
|
||||
<a target="_blank" href="https://github.com/minio/minio">
|
||||
GitHub <i className="fa fa-github" />
|
||||
GitHub <i className="fab fa-github" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" onClick={this.fullScreen}>
|
||||
Fullscreen <i className="fa fa-expand" />
|
||||
Fullscreen <i className="fas fa-expand" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a target="_blank" href="https://docs.min.io/">
|
||||
Documentation <i className="fa fa-book" />
|
||||
Documentation <i className="fas fa-book" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a target="_blank" href="https://slack.min.io">
|
||||
Ask for help <i className="fa fa-question-circle" />
|
||||
Ask for help <i className="fas fa-question-circle" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" id="show-about" onClick={this.showAbout.bind(this)}>
|
||||
About <i className="fa fa-info-circle" />
|
||||
About <i className="fas fa-info-circle" />
|
||||
</a>
|
||||
{this.state.showAboutModal && (
|
||||
<AboutModal
|
||||
@ -120,7 +120,7 @@ export class BrowserDropdown extends React.Component {
|
||||
</li>
|
||||
<li>
|
||||
<a href="" onClick={this.showChangePassword.bind(this)}>
|
||||
Change Password <i className="fa fa-cog" />
|
||||
Change Password <i className="fas fa-cog" />
|
||||
</a>
|
||||
{this.state.showChangePasswordModal && (
|
||||
<ChangePasswordModal
|
||||
@ -131,7 +131,7 @@ export class BrowserDropdown extends React.Component {
|
||||
</li>
|
||||
<li>
|
||||
<a href="" id="logout" onClick={this.logout}>
|
||||
Sign Out <i className="fa fa-sign-out" />
|
||||
Sign Out <i className="fas fa-sign-out-alt" />
|
||||
</a>
|
||||
</li>
|
||||
</Dropdown.Menu>
|
||||
|
@ -165,7 +165,7 @@ export class ChangePasswordModal extends React.Component {
|
||||
})
|
||||
}}
|
||||
className={
|
||||
"toggle-password fa fa-eye " +
|
||||
"toggle-password fas fa-eye " +
|
||||
(this.state.currentSecretKeyVisible ? "toggled" : "")
|
||||
}
|
||||
/>
|
||||
@ -211,7 +211,7 @@ export class ChangePasswordModal extends React.Component {
|
||||
})
|
||||
}}
|
||||
className={
|
||||
"toggle-password fa fa-eye " +
|
||||
"toggle-password fas fa-eye " +
|
||||
(this.state.newSecretKeyVisible ? "toggled" : "")
|
||||
}
|
||||
/>
|
||||
|
@ -18,7 +18,7 @@ import React from "react"
|
||||
|
||||
export const Host = () => (
|
||||
<div className="fes-host">
|
||||
<i className="fa fa-globe" />
|
||||
<i className="fas fa-globe-americas" />
|
||||
<a href="/">{window.location.host}</a>
|
||||
</div>
|
||||
)
|
||||
|
@ -125,7 +125,7 @@ export class Login extends React.Component {
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
<button className="lw-btn" type="submit">
|
||||
<i className="fa fa-sign-in" />
|
||||
<i className="fas fa-sign-in-alt" />
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -48,7 +48,7 @@ export const MainActions = ({
|
||||
<Dropdown dropup className="feb-actions" id="fe-action-toggle">
|
||||
<Dropdown.Toggle noCaret className="feba-toggle">
|
||||
<span>
|
||||
<i className="fa fa-plus" />
|
||||
<i className="fas fa-plus" />
|
||||
</span>
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu>
|
||||
@ -63,7 +63,7 @@ export const MainActions = ({
|
||||
/>
|
||||
<label htmlFor="file-input">
|
||||
{" "}
|
||||
<i className="fa fa-cloud-upload" />{" "}
|
||||
<i className="fas fa-cloud-upload-alt" />{" "}
|
||||
</label>
|
||||
</a>
|
||||
</OverlayTrigger>
|
||||
@ -78,7 +78,7 @@ export const MainActions = ({
|
||||
showMakeBucketModal()
|
||||
}}
|
||||
>
|
||||
<i className="fa fa-hdd-o" />
|
||||
<i className="far fa-hdd" />
|
||||
</a>
|
||||
</OverlayTrigger>
|
||||
)}
|
||||
|
@ -20,7 +20,6 @@ import ClickOutHandler from "react-onclickout"
|
||||
import { connect } from "react-redux"
|
||||
|
||||
import logo from "../../img/logo.svg"
|
||||
import Dropdown from "react-bootstrap/lib/Dropdown"
|
||||
import BucketSearch from "../buckets/BucketSearch"
|
||||
import BucketList from "../buckets/BucketList"
|
||||
import Host from "./Host"
|
||||
@ -28,8 +27,14 @@ import * as actionsCommon from "./actions"
|
||||
import web from "../web"
|
||||
|
||||
export const SideBar = ({ sidebarOpen, clickOutside }) => {
|
||||
const onClickOut = e => {
|
||||
if (e.target.classList.contains("feh-trigger")) {
|
||||
return
|
||||
}
|
||||
clickOutside()
|
||||
}
|
||||
return (
|
||||
<ClickOutHandler onClickOut={clickOutside}>
|
||||
<ClickOutHandler onClickOut={onClickOut}>
|
||||
<div
|
||||
className={classNames({
|
||||
"fe-sidebar": true,
|
||||
@ -62,4 +67,7 @@ const mapDispatchToProps = dispatch => {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SideBar)
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(SideBar)
|
||||
|
@ -35,7 +35,20 @@ describe("SideBar", () => {
|
||||
it("should call clickOutside when the user clicks outside the sidebar", () => {
|
||||
const clickOutside = jest.fn()
|
||||
const wrapper = shallow(<SideBar clickOutside={clickOutside} />)
|
||||
wrapper.simulate("clickOut", { preventDefault: jest.fn() })
|
||||
wrapper.simulate("clickOut", {
|
||||
preventDefault: jest.fn(),
|
||||
target: { classList: { contains: jest.fn(() => false) } }
|
||||
})
|
||||
expect(clickOutside).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should not call clickOutside when user clicks on sidebar toggle", () => {
|
||||
const clickOutside = jest.fn()
|
||||
const wrapper = shallow(<SideBar clickOutside={clickOutside} />)
|
||||
wrapper.simulate("clickOut", {
|
||||
preventDefault: jest.fn(),
|
||||
target: { classList: { contains: jest.fn(() => true) } }
|
||||
})
|
||||
expect(clickOutside).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
@ -29,7 +29,7 @@ let BrowserUpdate = ({latestUiVersion}) => {
|
||||
<a href="">
|
||||
<OverlayTrigger placement="left" overlay={ <Tooltip id="tt-version-update">
|
||||
New update available. Click to refresh.
|
||||
</Tooltip> }> <i className="fa fa-refresh"></i> </OverlayTrigger>
|
||||
</Tooltip> }> <i className="fas fa-sync"></i> </OverlayTrigger>
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
|
@ -23,7 +23,7 @@ export const DeleteObjectConfirmModal = ({
|
||||
}) => (
|
||||
<ConfirmModal
|
||||
show={true}
|
||||
icon="fa fa-exclamation-triangle mci-red"
|
||||
icon="fas fa-exclamation-triangle mci-red"
|
||||
text="Are you sure you want to delete?"
|
||||
sub="This cannot be undone!"
|
||||
okText="Delete"
|
||||
|
@ -67,14 +67,14 @@ export class ObjectActions extends React.Component {
|
||||
className="fiad-action"
|
||||
onClick={this.shareObject.bind(this)}
|
||||
>
|
||||
<i className="fa fa-share-alt" />
|
||||
<i className="fas fa-share-alt" />
|
||||
</a>
|
||||
<a
|
||||
href=""
|
||||
className="fiad-action"
|
||||
onClick={this.showDeleteConfirmModal.bind(this)}
|
||||
>
|
||||
<i className="fa fa-trash" />
|
||||
<i className="fas fa-trash-alt" />
|
||||
</a>
|
||||
</Dropdown.Menu>
|
||||
{(showShareObjectModal && shareObjectName === object.name) &&
|
||||
|
@ -59,7 +59,7 @@ export class ObjectsBulkActions extends React.Component {
|
||||
}
|
||||
>
|
||||
<span className="la-label">
|
||||
<i className="fa fa-check-circle" /> {checkedObjects.length}
|
||||
<i className="fas fa-check-circle" /> {checkedObjects.length}
|
||||
{checkedObjects.length === 1 ? " Object " : " Objects "}
|
||||
selected
|
||||
</span>
|
||||
@ -81,7 +81,7 @@ export class ObjectsBulkActions extends React.Component {
|
||||
</button>
|
||||
</span>
|
||||
<i
|
||||
className="la-close fa fa-times"
|
||||
className="la-close fas fa-times"
|
||||
id="close-bulk-actions"
|
||||
onClick={clearChecked}
|
||||
/>
|
||||
|
@ -47,9 +47,9 @@ export const ObjectsHeader = ({
|
||||
className={classNames({
|
||||
"fesli-sort": true,
|
||||
"fesli-sort--active": sortedByName,
|
||||
fa: true,
|
||||
"fa-sort-alpha-desc": sortedByName && sortOrder === SORT_ORDER_DESC,
|
||||
"fa-sort-alpha-asc": sortedByName && sortOrder === SORT_ORDER_ASC
|
||||
fas: true,
|
||||
"fa-sort-alpha-down-alt": sortedByName && sortOrder === SORT_ORDER_DESC,
|
||||
"fa-sort-alpha-down": sortedByName && sortOrder === SORT_ORDER_ASC
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
@ -64,10 +64,10 @@ export const ObjectsHeader = ({
|
||||
className={classNames({
|
||||
"fesli-sort": true,
|
||||
"fesli-sort--active": sortedBySize,
|
||||
fa: true,
|
||||
"fa-sort-amount-desc":
|
||||
fas: true,
|
||||
"fa-sort-amount-down":
|
||||
sortedBySize && sortOrder === SORT_ORDER_DESC,
|
||||
"fa-sort-amount-asc": sortedBySize && sortOrder === SORT_ORDER_ASC
|
||||
"fa-sort-amount-down-alt": sortedBySize && sortOrder === SORT_ORDER_ASC
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
@ -82,10 +82,10 @@ export const ObjectsHeader = ({
|
||||
className={classNames({
|
||||
"fesli-sort": true,
|
||||
"fesli-sort--active": sortedByLastModified,
|
||||
fa: true,
|
||||
"fa-sort-numeric-desc":
|
||||
fas: true,
|
||||
"fa-sort-numeric-down-alt":
|
||||
sortedByLastModified && sortOrder === SORT_ORDER_DESC,
|
||||
"fa-sort-numeric-asc":
|
||||
"fa-sort-numeric-down":
|
||||
sortedByLastModified && sortOrder === SORT_ORDER_ASC
|
||||
})}
|
||||
/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* MinIO Cloud Storage (C) 2016 MinIO, Inc.
|
||||
* MinIO Cloud Storage (C) 2016, 2018, 2019 MinIO, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,46 +16,146 @@
|
||||
|
||||
import React from "react"
|
||||
import { connect } from "react-redux"
|
||||
import ClickOutHandler from "react-onclickout"
|
||||
import { OverlayTrigger, Tooltip } from "react-bootstrap"
|
||||
import { getCurrentBucket } from "../buckets/selectors"
|
||||
import * as actionsObjects from "./actions"
|
||||
import * as actionsBuckets from "../buckets/actions"
|
||||
|
||||
export const Path = ({ currentBucket, currentPrefix, selectPrefix }) => {
|
||||
const onPrefixClick = (e, prefix) => {
|
||||
e.preventDefault()
|
||||
selectPrefix(prefix)
|
||||
export class Path extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
isEditing: false,
|
||||
path: ""
|
||||
}
|
||||
}
|
||||
let dirPath = []
|
||||
let path = ""
|
||||
if (currentPrefix) {
|
||||
path = currentPrefix.split("/").map((dir, i) => {
|
||||
if (dir) {
|
||||
dirPath.push(dir)
|
||||
let dirPath_ = dirPath.join("/") + "/"
|
||||
return (
|
||||
<span key={i}>
|
||||
<a href="" onClick={e => onPrefixClick(e, dirPath_)}>
|
||||
{dir}
|
||||
</a>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
stopEditing() {
|
||||
this.setState({
|
||||
isEditing: false
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<h2>
|
||||
<span className="main">
|
||||
<a onClick={e => onPrefixClick(e, "")} href="">
|
||||
{currentBucket}
|
||||
</a>
|
||||
</span>
|
||||
{path}
|
||||
</h2>
|
||||
)
|
||||
onPrefixClick(e, prefix) {
|
||||
e.preventDefault()
|
||||
const { selectPrefix } = this.props
|
||||
selectPrefix(prefix)
|
||||
}
|
||||
onEditClick(e) {
|
||||
e.preventDefault()
|
||||
const { currentBucket, currentPrefix } = this.props
|
||||
this.setState(
|
||||
{
|
||||
isEditing: true,
|
||||
path: `${currentBucket}/${currentPrefix}`
|
||||
},
|
||||
() => {
|
||||
// focus on input and move cursor to the end
|
||||
this.pathInput.focus()
|
||||
this.pathInput.setSelectionRange(
|
||||
this.state.path.length,
|
||||
this.state.path.length
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
onKeyDown(e) {
|
||||
// When Esc key is pressed
|
||||
if (e.keyCode === 27) {
|
||||
this.stopEditing()
|
||||
}
|
||||
}
|
||||
onInputClickOut() {
|
||||
this.stopEditing()
|
||||
}
|
||||
bucketExists(bucketName) {
|
||||
const { buckets } = this.props
|
||||
return buckets.includes(bucketName)
|
||||
}
|
||||
async onSubmit(e) {
|
||||
e.preventDefault()
|
||||
const { makeBucket, selectBucket } = this.props
|
||||
// all paths need to end in slash to display contents properly
|
||||
let path = this.state.path
|
||||
if (!path.endsWith("/")) {
|
||||
path += "/"
|
||||
}
|
||||
const splittedPath = path.split("/")
|
||||
if (splittedPath.length > 0) {
|
||||
// prevent bucket name from being empty
|
||||
if (splittedPath[0]) {
|
||||
const bucketName = splittedPath[0]
|
||||
const prefix = splittedPath.slice(1).join("/")
|
||||
if (!this.bucketExists(bucketName)) {
|
||||
await makeBucket(bucketName)
|
||||
}
|
||||
// check updated buckets and don't proceed on invalid inputs
|
||||
if (this.bucketExists(bucketName)) {
|
||||
// then select bucket with prefix
|
||||
selectBucket(bucketName, prefix)
|
||||
}
|
||||
this.stopEditing()
|
||||
}
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const pathTooltip = <Tooltip id="tt-path">Choose or create new path</Tooltip>
|
||||
const { currentBucket, currentPrefix } = this.props
|
||||
let dirPath = []
|
||||
let path = ""
|
||||
if (currentPrefix) {
|
||||
path = currentPrefix.split("/").map((dir, i) => {
|
||||
if (dir) {
|
||||
dirPath.push(dir)
|
||||
let dirPath_ = dirPath.join("/") + "/"
|
||||
return (
|
||||
<span key={i}>
|
||||
<a href="" onClick={e => this.onPrefixClick(e, dirPath_)}>
|
||||
{dir}
|
||||
</a>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
return (
|
||||
<h2>
|
||||
{this.state.isEditing ? (
|
||||
<ClickOutHandler onClickOut={() => this.onInputClickOut()}>
|
||||
<form onSubmit={e => this.onSubmit(e)}>
|
||||
<input
|
||||
className="form-control form-control--path"
|
||||
type="text"
|
||||
placeholder="Choose or create new path"
|
||||
ref={node => (this.pathInput = node)}
|
||||
onKeyDown={e => this.onKeyDown(e)}
|
||||
value={this.state.path}
|
||||
onChange={e => this.setState({ path: e.target.value })}
|
||||
/>
|
||||
</form>
|
||||
</ClickOutHandler>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<span className="main">
|
||||
<a href="" onClick={e => this.onPrefixClick(e, "")}>
|
||||
{currentBucket}
|
||||
</a>
|
||||
</span>
|
||||
{path}
|
||||
<OverlayTrigger placement="bottom" overlay={pathTooltip}>
|
||||
<a href="" onClick={e => this.onEditClick(e)} className="fe-edit">
|
||||
<i className="fas fa-folder-plus" />
|
||||
</a>
|
||||
</OverlayTrigger>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</h2>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
buckets: state.buckets.list,
|
||||
currentBucket: getCurrentBucket(state),
|
||||
currentPrefix: state.objects.currentPrefix
|
||||
}
|
||||
@ -63,8 +163,14 @@ const mapStateToProps = state => {
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
makeBucket: bucket => dispatch(actionsBuckets.makeBucket(bucket)),
|
||||
selectBucket: (bucket, prefix) =>
|
||||
dispatch(actionsBuckets.selectBucket(bucket, prefix)),
|
||||
selectPrefix: prefix => dispatch(actionsObjects.selectPrefix(prefix))
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Path)
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Path)
|
||||
|
@ -35,7 +35,7 @@ describe("ObjectsHeader", () => {
|
||||
/>
|
||||
)
|
||||
expect(
|
||||
wrapper.find("#sort-by-name i").hasClass("fa-sort-alpha-asc")
|
||||
wrapper.find("#sort-by-name i").hasClass("fa-sort-alpha-down")
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
@ -49,7 +49,7 @@ describe("ObjectsHeader", () => {
|
||||
/>
|
||||
)
|
||||
expect(
|
||||
wrapper.find("#sort-by-name i").hasClass("fa-sort-alpha-desc")
|
||||
wrapper.find("#sort-by-name i").hasClass("fa-sort-alpha-down-alt")
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
@ -63,7 +63,7 @@ describe("ObjectsHeader", () => {
|
||||
/>
|
||||
)
|
||||
expect(
|
||||
wrapper.find("#sort-by-size i").hasClass("fa-sort-amount-asc")
|
||||
wrapper.find("#sort-by-size i").hasClass("fa-sort-amount-down-alt")
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
@ -77,7 +77,7 @@ describe("ObjectsHeader", () => {
|
||||
/>
|
||||
)
|
||||
expect(
|
||||
wrapper.find("#sort-by-size i").hasClass("fa-sort-amount-desc")
|
||||
wrapper.find("#sort-by-size i").hasClass("fa-sort-amount-down")
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
@ -91,7 +91,7 @@ describe("ObjectsHeader", () => {
|
||||
/>
|
||||
)
|
||||
expect(
|
||||
wrapper.find("#sort-by-last-modified i").hasClass("fa-sort-numeric-asc")
|
||||
wrapper.find("#sort-by-last-modified i").hasClass("fa-sort-numeric-down")
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
@ -105,7 +105,7 @@ describe("ObjectsHeader", () => {
|
||||
/>
|
||||
)
|
||||
expect(
|
||||
wrapper.find("#sort-by-last-modified i").hasClass("fa-sort-numeric-desc")
|
||||
wrapper.find("#sort-by-last-modified i").hasClass("fa-sort-numeric-down-alt")
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import React from "react"
|
||||
import { shallow } from "enzyme"
|
||||
import { shallow, mount } from "enzyme"
|
||||
import { Path } from "../Path"
|
||||
|
||||
describe("Path", () => {
|
||||
@ -26,7 +26,12 @@ describe("Path", () => {
|
||||
it("should render only bucket if there is no prefix", () => {
|
||||
const wrapper = shallow(<Path currentBucket={"test1"} currentPrefix={""} />)
|
||||
expect(wrapper.find("span").length).toBe(1)
|
||||
expect(wrapper.text()).toBe("test1")
|
||||
expect(
|
||||
wrapper
|
||||
.find("span")
|
||||
.at(0)
|
||||
.text()
|
||||
).toBe("test1")
|
||||
})
|
||||
|
||||
it("should render bucket and prefix", () => {
|
||||
@ -69,4 +74,70 @@ describe("Path", () => {
|
||||
.simulate("click", { preventDefault: jest.fn() })
|
||||
expect(selectPrefix).toHaveBeenCalledWith("a/b/")
|
||||
})
|
||||
|
||||
it("should switch to input mode when edit icon is clicked", () => {
|
||||
const wrapper = mount(<Path currentBucket={"test1"} currentPrefix={""} />)
|
||||
wrapper.find(".fe-edit").simulate("click", { preventDefault: jest.fn() })
|
||||
expect(wrapper.find(".form-control--path").exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it("should navigate to prefix when user types path for existing bucket", () => {
|
||||
const selectBucket = jest.fn()
|
||||
const buckets = ["test1", "test2"]
|
||||
const wrapper = mount(
|
||||
<Path
|
||||
buckets={buckets}
|
||||
currentBucket={"test1"}
|
||||
currentPrefix={""}
|
||||
selectBucket={selectBucket}
|
||||
/>
|
||||
)
|
||||
wrapper.setState({
|
||||
isEditing: true,
|
||||
path: "test2/dir1/"
|
||||
})
|
||||
wrapper.find("form").simulate("submit", { preventDefault: jest.fn() })
|
||||
expect(selectBucket).toHaveBeenCalledWith("test2", "dir1/")
|
||||
})
|
||||
|
||||
it("should create a new bucket if bucket typed in path doesn't exist", () => {
|
||||
const makeBucket = jest.fn()
|
||||
const buckets = ["test1", "test2"]
|
||||
const wrapper = mount(
|
||||
<Path
|
||||
buckets={buckets}
|
||||
currentBucket={"test1"}
|
||||
currentPrefix={""}
|
||||
makeBucket={makeBucket}
|
||||
/>
|
||||
)
|
||||
wrapper.setState({
|
||||
isEditing: true,
|
||||
path: "test3/dir1/"
|
||||
})
|
||||
wrapper.find("form").simulate("submit", { preventDefault: jest.fn() })
|
||||
expect(makeBucket).toHaveBeenCalledWith("test3")
|
||||
})
|
||||
|
||||
it("should not make or select bucket if path doesn't point to bucket", () => {
|
||||
const makeBucket = jest.fn()
|
||||
const selectBucket = jest.fn()
|
||||
const buckets = ["test1", "test2"]
|
||||
const wrapper = mount(
|
||||
<Path
|
||||
buckets={buckets}
|
||||
currentBucket={"test1"}
|
||||
currentPrefix={""}
|
||||
makeBucket={makeBucket}
|
||||
selectBucket={selectBucket}
|
||||
/>
|
||||
)
|
||||
wrapper.setState({
|
||||
isEditing: true,
|
||||
path: "//dir1/dir2/"
|
||||
})
|
||||
wrapper.find("form").simulate("submit", { preventDefault: jest.fn() })
|
||||
expect(makeBucket).not.toHaveBeenCalled()
|
||||
expect(selectBucket).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
@ -33,12 +33,12 @@ export class AbortConfirmModal extends React.Component {
|
||||
"abort-upload": true
|
||||
})
|
||||
let okIcon = classNames({
|
||||
fa: true,
|
||||
fas: true,
|
||||
"fa-times": true
|
||||
})
|
||||
let cancelIcon = classNames({
|
||||
fa: true,
|
||||
"fa-cloud-upload": true
|
||||
fas: true,
|
||||
"fa-cloud-upload-alt": true
|
||||
})
|
||||
|
||||
return (
|
||||
@ -46,7 +46,7 @@ export class AbortConfirmModal extends React.Component {
|
||||
show={true}
|
||||
baseClass={baseClass}
|
||||
text="Abort uploads in progress?"
|
||||
icon="fa fa-info-circle mci-amber"
|
||||
icon="fas fa-info-circle mci-amber"
|
||||
sub="This cannot be undone!"
|
||||
okText="Abort"
|
||||
okIcon={okIcon}
|
||||
|
@ -8,6 +8,13 @@
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.form-control--path {
|
||||
color: @link-color;
|
||||
padding: 5px 5px 6px 0;
|
||||
font-size: 16px;
|
||||
.placeholder(@text-muted-color)
|
||||
}
|
||||
|
||||
select.form-control {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
@ -153,7 +160,7 @@ select.form-control {
|
||||
}
|
||||
&:after {
|
||||
content: "\f05a";
|
||||
font-family: FontAwesome;
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
position: absolute;
|
||||
top: 17px;
|
||||
right: 9px;
|
||||
@ -165,6 +172,7 @@ select.form-control {
|
||||
.ig-search {
|
||||
&:before {
|
||||
font-family: @font-family-icon;
|
||||
font-weight: 900;
|
||||
content: '\f002';
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
|
@ -16,6 +16,10 @@
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
|
||||
@media(min-width: (@screen-md-min)) {
|
||||
width: calc(100% - 60px);
|
||||
}
|
||||
|
||||
& > span {
|
||||
margin-bottom: 7px;
|
||||
display: inline-block;
|
||||
@ -27,7 +31,7 @@
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
&:last-of-type {
|
||||
&:after {
|
||||
content: '/';
|
||||
margin: 0 4px;
|
||||
@ -43,6 +47,19 @@
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------
|
||||
Edit path
|
||||
----------------------------*/
|
||||
.fe-edit {
|
||||
font-size: 20px;
|
||||
color: @link-color;
|
||||
margin-left: 4px;
|
||||
|
||||
i {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------
|
||||
Disk used
|
||||
----------------------------*/
|
||||
@ -132,7 +149,7 @@
|
||||
@media(max-width: (@screen-sm-max)) {
|
||||
background: url(../../img/more-h-light.svg) no-repeat center;
|
||||
|
||||
.fa-reorder {
|
||||
.fa-bars {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ div.fesl-row {
|
||||
Icons
|
||||
----------------------------*/
|
||||
&[data-type=folder] {
|
||||
.list-type(#a1d6dd, '\f114');
|
||||
.list-type(#a1d6dd, '\f07b');
|
||||
|
||||
.fesl-item-name {
|
||||
a {
|
||||
@ -128,8 +128,8 @@ div.fesl-row {
|
||||
&[data-type=excel] { .list-type(#64c866, '\f1c3'); }
|
||||
&[data-type=image] { .list-type(#f06292, '\f1c5'); }
|
||||
&[data-type=video] { .list-type(#f8c363, '\f1c8'); }
|
||||
&[data-type=other] { .list-type(#afafaf, '\f016'); }
|
||||
&[data-type=text] { .list-type(#8a8a8a, '\f0f6'); }
|
||||
&[data-type=other] { .list-type(#afafaf, '\f15b'); }
|
||||
&[data-type=text] { .list-type(#8a8a8a, '\f15c'); }
|
||||
&[data-type=doc] { .list-type(#2196f5, '\f1c2'); }
|
||||
&[data-type=presentation] { .list-type(#896ea6, '\f1c4'); }
|
||||
|
||||
@ -249,6 +249,7 @@ div.fesl-row {
|
||||
|
||||
&:after {
|
||||
font-family: @font-family-icon;
|
||||
font-weight: 900;
|
||||
content: '\f00c';
|
||||
top: 8px;
|
||||
left: 9px;
|
||||
@ -449,7 +450,7 @@ div.fesl-row {
|
||||
float: left;
|
||||
padding: 4px 0;
|
||||
|
||||
.fa {
|
||||
.fas {
|
||||
font-size: 22px;
|
||||
vertical-align: top;
|
||||
margin-right: 10px;
|
||||
|
@ -76,7 +76,7 @@
|
||||
word-wrap: break-word;
|
||||
|
||||
&:before {
|
||||
font-family: FontAwesome;
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
content: '\f0a0';
|
||||
font-size: 17px;
|
||||
position: absolute;
|
||||
|
@ -2,7 +2,7 @@
|
||||
Base
|
||||
----------------------------*/
|
||||
@font-family-sans-serif : 'Lato', sans-serif;
|
||||
@font-family-icon : 'fontAwesome';
|
||||
@font-family-icon : 'Font Awesome 5 Free';
|
||||
@body-bg : #edecec;
|
||||
@text-color : #8e8e8e;
|
||||
@font-size-base : 15px;
|
||||
|
16
browser/package-lock.json
generated
16
browser/package-lock.json
generated
@ -82,6 +82,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@fortawesome/fontawesome-free": {
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.10.0.tgz",
|
||||
"integrity": "sha512-XX16koDMY/tkJmec0VFfKF7RYZOze/203B1iyLnRaAySm3ZPhKaeyIpf73Yh8xhrMk3Fj4TeH3FC01qyFTyg8g=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "12.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.7.tgz",
|
||||
@ -4571,11 +4576,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"font-awesome": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
|
||||
"integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM="
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||
@ -10403,9 +10403,9 @@
|
||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||
},
|
||||
"react-onclickout": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-onclickout/-/react-onclickout-2.0.4.tgz",
|
||||
"integrity": "sha1-LHU5pkfh3NyrCyji9Orjw+APDGQ="
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/react-onclickout/-/react-onclickout-2.0.8.tgz",
|
||||
"integrity": "sha1-0XixP7h6SBNWdhtFSqYN9wabLaQ="
|
||||
},
|
||||
"react-overlays": {
|
||||
"version": "0.8.3",
|
||||
|
@ -59,10 +59,10 @@
|
||||
"webpack-dev-server": "^3.1.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.10.0",
|
||||
"bootstrap": "^3.3.6",
|
||||
"classnames": "^2.2.3",
|
||||
"expect": "^1.20.2",
|
||||
"font-awesome": "^4.7.0",
|
||||
"glob-all": "^3.1.0",
|
||||
"history": "^4.7.2",
|
||||
"humanize": "0.0.9",
|
||||
@ -82,7 +82,7 @@
|
||||
"react-dom": "^16.2.0",
|
||||
"react-dropzone": "^4.2.3",
|
||||
"react-infinite-scroller": "^1.0.6",
|
||||
"react-onclickout": "2.0.4",
|
||||
"react-onclickout": "^2.0.8",
|
||||
"react-redux": "^5.0.6",
|
||||
"react-router-dom": "^4.2.0",
|
||||
"redux": "^3.7.2",
|
||||
|
File diff suppressed because one or more lines are too long
@ -10,6 +10,11 @@
|
||||
esutils "^2.0.2"
|
||||
js-tokens "^3.0.0"
|
||||
|
||||
"@fortawesome/fontawesome-free@^5.10.0":
|
||||
version "5.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.10.0.tgz#dbfb34093c87c9516f03ee1db3385adae3ae9461"
|
||||
integrity sha512-XX16koDMY/tkJmec0VFfKF7RYZOze/203B1iyLnRaAySm3ZPhKaeyIpf73Yh8xhrMk3Fj4TeH3FC01qyFTyg8g==
|
||||
|
||||
"@types/node@*":
|
||||
version "9.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.0.tgz#b85a0bcf1e1cc84eb4901b7e96966aedc6f078d1"
|
||||
@ -3230,10 +3235,6 @@ follow-redirects@^1.0.0:
|
||||
dependencies:
|
||||
debug "=3.1.0"
|
||||
|
||||
font-awesome@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
|
||||
|
||||
for-in@^1.0.1, for-in@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||
|
Loading…
Reference in New Issue
Block a user