/* * MinIO Object Storage (c) 2021 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 { 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 class Path extends React.Component { constructor(props) { super(props) this.state = { isEditing: false, path: "" } } stopEditing() { this.setState({ isEditing: false }) } 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 = Choose or create new path 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 ( this.onPrefixClick(e, dirPath_)}> {dir} ) } }) } return (

{this.state.isEditing ? ( this.onInputClickOut()}>
this.onSubmit(e)}> (this.pathInput = node)} onKeyDown={e => this.onKeyDown(e)} value={this.state.path} onChange={e => this.setState({ path: e.target.value })} />
) : ( this.onPrefixClick(e, "")}> {currentBucket} {path} this.onEditClick(e)} className="fe-edit"> )}

) } } const mapStateToProps = state => { return { buckets: state.buckets.list, currentBucket: getCurrentBucket(state), currentPrefix: state.objects.currentPrefix } } 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)