Newer
Older
/*
* Copyright ETH 2023 Zürich, Scientific IT Services
*
* 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 ResizeObserver from 'rc-resize-observer'
import Button from '@material-ui/core/Button'
import CreateNewFolderIcon from '@material-ui/icons/CreateNewFolderOutlined'
import DownloadIcon from '@material-ui/icons/GetApp'
import DeleteIcon from '@material-ui/icons/Delete'
import RenameIcon from '@material-ui/icons/Create'
import CopyIcon from '@material-ui/icons/FileCopy'
import MoveIcon from '@material-ui/icons/ArrowRightAlt'
import MoreIcon from '@material-ui/icons/MoreVert'
import messages from '@src/js/common/messages.js'
import { withStyles } from '@material-ui/core/styles'
import logger from '@src/js/common/logger.js'
import autoBind from 'auto-bind'
import IconButton from '@material-ui/core/IconButton'
import { debounce } from '@material-ui/core'
import Container from '@src/js/components/common/form/Container.jsx'
import Popover from '@material-ui/core/Popover'
import InputDialog from '@src/js/components/common/dialog/InputDialog.jsx'
import ConfirmationDialog from "@src/js/components/common/dialog/ConfirmationDialog.jsx";
const iconButtonSize = 'medium'
const styles = theme => ({
buttons: {
flex: '1 1 auto',
display: 'flex',
alignItems: 'center',
overflow: 'hidden',
'&>button': {
marginRight: theme.spacing(1)
},
'&>button:nth-last-child(1)': {
marginRight: 0
}
toggleButton: {},
collapsedButtonsContainer: {
display: 'flex',
flexDirection: 'column',
'&>button': {
marginBottom: theme.spacing(1)
},
'&>button:nth-last-child(1)': {
marginBottom: 0
}
},
})
class LeftToolbar extends React.Component {
constructor(props, context) {
super(props, context)
autoBind(this)
this.state = {
width: 0,
newFolderDialogOpen: false,
deleteDialogOpen: false
}
this.controller = this.props.controller
this.onResize = debounce(this.onResize, 1)
}
async handleNewFolderCreate(folderName) {
await this.controller.createNewFolder(folderName)
handleNewFolderCancel() {
this.closeNewFolderDialog()
}
openNewFolderDialog() {
this.setState({ newFolderDialogOpen: true })
}
closeNewFolderDialog() {
this.setState({ newFolderDialogOpen: false })
}
openDeleteDialog() {
this.setState({ deleteDialogOpen: true })
}
closeDeleteDialog() {
this.setState({ deleteDialogOpen: false })
}
async handleDeleteConfirm() {
const { multiselectedFiles } = this.props
this.closeDeleteDialog()
await this.controller.delete(Array.from(multiselectedFiles).map((file) => file.path))
}
handleDeleteCancel() {
this.closeDeleteDialog()
}
renderNoSelectionContextToolbar() {
const { classes, buttonSize } = this.props
<Button
classes={{ root: classes.button }}
color={color}
size={buttonSize}
variant='outlined'
startIcon={<CreateNewFolderIcon />}
onClick={this.openNewFolderDialog}
>
{messages.get(messages.NEW_FOLDER)}
</Button>,
<InputDialog
key='new-folder-dialog'
open={this.state.newFolderDialogOpen}
title={messages.get(messages.NEW_FOLDER)}
inputLabel={messages.get(messages.FOLDER_NAME)}
onConfirm={this.handleNewFolderCreate}
/>
])
renderSelectionContextToolbar() {
const { classes, buttonSize, multiselectedFiles } = this.props
const { width, hiddenButtonsPopup, deleteDialogOpen } = this.state
const ellipsisButtonSize = 24
const buttonsCount = 5
const minSize = 500
const roughButtonSize = Math.floor(minSize / buttonsCount)
const hideButtons = width < minSize
vkovtun
committed
const visibleButtonsCount = Math.max(hideButtons ? Math.floor((width - 3 * ellipsisButtonSize) / roughButtonSize) : buttonsCount, 0)
const buttons = [
<Button
classes={{ root: classes.button }}
color={color}
size={buttonSize}
variant='outlined'
startIcon={<DownloadIcon />}
>
{messages.get(messages.DOWNLOAD)}
</Button>,
<Button
classes={{ root: classes.button }}
color={color}
size={buttonSize}
variant='text'
startIcon={<DeleteIcon />}
>
{messages.get(messages.DELETE)}
</Button>,
<Button
classes={{ root: classes.button }}
color={color}
size={buttonSize}
variant='text'
disabled={multiselectedFiles.size !== 1}
startIcon={<RenameIcon />}
>
{messages.get(messages.RENAME)}
</Button>,
<Button
classes={{ root: classes.button }}
color={color}
size={buttonSize}
variant='text'
startIcon={<CopyIcon />}
>
{messages.get(messages.COPY)}
</Button>,
<Button
classes={{ root: classes.button }}
color={color}
size={buttonSize}
variant='text'
startIcon={<MoveIcon />}
>
{messages.get(messages.MOVE)}
</Button>
]
const ellipsisButton = (
<IconButton
key='ellipsis'
classes={{ root: classes.button }}
color={color}
size={iconButtonSize}
variant='outlined'
onClick={this.handleOpen}
>
<MoreIcon />
</IconButton>
)
const popover = (
<Popover
open={Boolean(hiddenButtonsPopup)}
anchorEl={hiddenButtonsPopup}
onClose={this.handleClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left'
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left'
}}
>
<Container square={true}>{this.renderCollapsedButtons(buttons.slice(visibleButtonsCount))}</Container>
</Popover>
)
return (
<div className={classes.buttons}>
{hideButtons
? [...buttons.slice(0, visibleButtonsCount), ellipsisButton, popover]
: buttons}
<ConfirmationDialog
open={deleteDialogOpen}
onConfirm={this.handleDeleteConfirm}
onCancel={this.handleDeleteCancel}
title={messages.get(messages.DELETE)}
content={messages.get(messages.CONFIRMATION_DELETE_SELECTED)}
/>
</div>
);
}
renderCollapsedButtons(buttons) {
const { classes } = this.props
return (
<div className={classes.collapsedButtonsContainer}>
{buttons}
</div>
)
}
onResize({ width }) {
if (width !== this.state.width) {
this.setState({ width, hiddenButtonsPopup: null })
}
}
handleOpen(event) {
this.setState({
hiddenButtonsPopup: event.currentTarget
})
}
handleClose() {
this.setState({
hiddenButtonsPopup: null
})
}
render() {
logger.log(logger.DEBUG, 'LeftToolbar.render')
const { multiselectedFiles, classes } = this.props
return (
<ResizeObserver onResize={this.onResize}>
<div className={classes.buttons}>
{multiselectedFiles && multiselectedFiles.size > 0
? this.renderSelectionContextToolbar()
: this.renderNoSelectionContextToolbar()}
</div>
</ResizeObserver>
)
}
}
export default withStyles(styles)(LeftToolbar)