1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-17 07:41:26 +00:00

Double name bug repair (#2879)

This commit is contained in:
杨顺强
2019-01-25 15:44:04 +08:00
committed by Daniel Pan
parent 9ddcf06225
commit 69b4db2afa
12 changed files with 222 additions and 91 deletions

View File

@@ -1,12 +1,14 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Modal, ModalHeader, Input, ModalBody, ModalFooter, Form, FormGroup, Label } from 'reactstrap';
import { Button, Modal, ModalHeader, Input, ModalBody, ModalFooter, Form, FormGroup, Label, Alert } from 'reactstrap';
import { gettext } from '../../utils/constants';
import { Utils } from '../../utils/utils';
const propTypes = {
fileType: PropTypes.string,
parentPath: PropTypes.string.isRequired,
onAddFile: PropTypes.func.isRequired,
checkDuplicatedName: PropTypes.func.isRequired,
addFileCancel: PropTypes.func.isRequired,
};
@@ -17,10 +19,22 @@ class CreateFile extends React.Component {
parentPath: '',
childName: props.fileType,
isDraft: false,
errMessage: '',
};
this.newInput = React.createRef();
}
componentDidMount() {
let parentPath = this.props.parentPath;
if (parentPath[parentPath.length - 1] === '/') { // mainPanel
this.setState({parentPath: parentPath});
} else {
this.setState({parentPath: parentPath + '/'}); // sidePanel
}
this.newInput.focus();
this.newInput.setSelectionRange(0,0);
}
handleChange = (e) => {
this.setState({
childName: e.target.value,
@@ -28,14 +42,23 @@ class CreateFile extends React.Component {
}
handleSubmit = () => {
let path = this.state.parentPath + this.state.childName;
let isDraft = this.state.isDraft;
this.props.onAddFile(path, isDraft);
let isDuplicated = this.checkDuplicatedName();
let newName = this.state.childName
if (isDuplicated) {
let errMessage = gettext('The name \'{name}\' is already occupied, please choose another name.');
errMessage = errMessage.replace('{name}', Utils.HTMLescape(newName));
this.setState({errMessage: errMessage});
} else {
let path = this.state.parentPath + newName;
let isDraft = this.state.isDraft;
this.props.onAddFile(path, isDraft);
}
}
handleKeyPress = (e) => {
if (e.key === 'Enter') {
this.handleSubmit();
e.preventDefault();
}
}
@@ -92,15 +115,9 @@ class CreateFile extends React.Component {
this.props.addFileCancel();
}
componentDidMount() {
let parentPath = this.props.parentPath;
if (parentPath[parentPath.length - 1] === '/') { // mainPanel
this.setState({parentPath: parentPath});
} else {
this.setState({parentPath: parentPath + '/'}); // sidePanel
}
this.newInput.focus();
this.newInput.setSelectionRange(0,0);
checkDuplicatedName = () => {
let isDuplicated = this.props.checkDuplicatedName(this.state.childName);
return isDuplicated;
}
render() {
@@ -127,6 +144,7 @@ class CreateFile extends React.Component {
</FormGroup>
)}
</Form>
{this.state.errMessage && <Alert color="danger" className="mt-2">{this.state.errMessage}</Alert>}
</ModalBody>
<ModalFooter>
<Button color="secondary" onClick={this.toggle}>{gettext('Cancel')}</Button>

View File

@@ -1,12 +1,14 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Modal, ModalHeader, Input, ModalBody, ModalFooter, Form, FormGroup, Label } from 'reactstrap';
import { Button, Modal, ModalHeader, Input, ModalBody, ModalFooter, Form, FormGroup, Label, Alert } from 'reactstrap';
import { gettext } from '../../utils/constants';
import { Utils } from '../../utils/utils';
const propTypes = {
fileType: PropTypes.string,
parentPath: PropTypes.string.isRequired,
onAddFolder: PropTypes.func.isRequired,
checkDuplicatedName: PropTypes.func.isRequired,
addFolderCancel: PropTypes.func.isRequired,
};
@@ -15,32 +17,12 @@ class CreateForder extends React.Component {
super(props);
this.state = {
parentPath: '',
childName: ''
childName: '',
errMessage: ''
};
this.newInput = React.createRef();
}
handleChange = (e) => {
this.setState({
childName: e.target.value,
});
}
handleSubmit = () => {
let path = this.state.parentPath + this.state.childName;
this.props.onAddFolder(path);
}
handleKeyPress = (e) => {
if (e.key === 'Enter') {
this.handleSubmit();
}
}
toggle = () => {
this.props.addFolderCancel();
}
componentDidMount() {
let parentPath = this.props.parentPath;
if (parentPath[parentPath.length - 1] === '/') { // mainPanel
@@ -52,6 +34,39 @@ class CreateForder extends React.Component {
this.newInput.setSelectionRange(0,0);
}
handleChange = (e) => {
this.setState({childName: e.target.value});
}
handleSubmit = () => {
let newName = this.state.childName;
let isDuplicated = this.checkDuplicatedName();
if (isDuplicated) {
let errMessage = gettext('The name \'{name}\' is already occupied, please choose another name.');
errMessage = errMessage.replace('{name}', Utils.HTMLescape(newName));
this.setState({errMessage: errMessage});
} else {
let path = this.state.parentPath + newName;
this.props.onAddFolder(path);
}
}
handleKeyPress = (e) => {
if (e.key === 'Enter') {
this.handleSubmit();
e.preventDefault();
}
}
toggle = () => {
this.props.addFolderCancel();
}
checkDuplicatedName = () => {
let isDuplicated = this.props.checkDuplicatedName(this.state.childName);
return isDuplicated;
}
render() {
return (
<Modal isOpen={true} toggle={this.toggle}>
@@ -69,6 +84,7 @@ class CreateForder extends React.Component {
/>
</FormGroup>
</Form>
{this.state.errMessage && <Alert color="danger" className="mt-2">{this.state.errMessage}</Alert>}
</ModalBody>
<ModalFooter>
<Button color="secondary" onClick={this.toggle}>{gettext('Cancel')}</Button>

View File

@@ -1,12 +1,14 @@
import React from 'react';
import PropTypes from 'prop-types';
import { gettext } from '../../utils/constants';
import { Button, Modal, ModalHeader, Input, ModalBody, ModalFooter } from 'reactstrap';
import { Utils } from '../../utils/utils';
import { Button, Modal, ModalHeader, Input, ModalBody, ModalFooter, Alert } from 'reactstrap';
const propTypes = {
currentNode: PropTypes.object,
onRename: PropTypes.func.isRequired,
toggleCancel: PropTypes.func.isRequired,
checkDuplicatedName: PropTypes.func.isRequired,
};
class Rename extends React.Component {
@@ -14,34 +16,13 @@ class Rename extends React.Component {
super(props);
this.state = {
newName: '',
errMessage: '',
};
this.newInput = React.createRef();
}
handleChange = (e) => {
this.setState({
newName: e.target.value,
});
}
handleSubmit = () => {
this.props.onRename(this.state.newName);
}
handleKeyPress = (e) => {
if (e.key === 'Enter') {
this.handleSubmit();
}
}
toggle = () => {
this.props.toggleCancel();
}
componentWillMount() {
this.setState({
newName: this.props.currentNode.object.name
});
this.setState({newName: this.props.currentNode.object.name});
}
componentDidMount() {
@@ -60,12 +41,66 @@ class Rename extends React.Component {
componentWillReceiveProps(nextProps) {
this.changeState(nextProps.currentNode);
}
handleChange = (e) => {
this.setState({newName: e.target.value});
}
changeState(currentNode) {
handleSubmit = () => {
let { isValid, errMessage } = this.validateInput();
if (!isValid) {
this.setState({errMessage : errMessage});
} else {
let isDuplicated = this.checkDuplicatedName();
if (isDuplicated) {
let errMessage = gettext('The name \'{name}\' is already occupied, please choose another name.');
errMessage = errMessage.replace('{name}', Utils.HTMLescape(this.state.newName));
this.setState({errMessage: errMessage});
} else {
this.props.onRename(this.state.newName);
}
}
}
handleKeyPress = (e) => {
if (e.key === 'Enter') {
this.handleSubmit();
}
}
toggle = () => {
this.props.toggleCancel();
}
changeState = (currentNode) => {
let name = currentNode.object.name;
this.setState({newName: name});
}
validateInput = () => {
let newName = this.state.newName.trim();
let isValid = true;
let errMessage = '';
if (!newName) {
isValid = false;
errMessage = gettext('Name is required.');
return { isValid, errMessage };
}
if (newName.indexOf('/') > -1) {
isValid = false;
errMessage = gettext('Name should not include ' + '\'/\'' + '.');
return { isValid, errMessage };
}
return { isValid, errMessage };
}
checkDuplicatedName = () => {
let isDuplicated = this.props.checkDuplicatedName(this.state.newName);
return isDuplicated;
}
render() {
let type = this.props.currentNode.object.type;
return (
@@ -74,6 +109,7 @@ class Rename extends React.Component {
<ModalBody>
<p>{type === 'file' ? gettext('Enter the new file name:'): gettext('Enter the new folder name:')}</p>
<Input onKeyPress={this.handleKeyPress} innerRef={input => {this.newInput = input;}} placeholder="newName" value={this.state.newName} onChange={this.handleChange} />
{this.state.errMessage && <Alert color="danger" className="mt-2">{this.state.errMessage}</Alert>}
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={this.handleSubmit}>{gettext('Submit')}</Button>

View File

@@ -157,6 +157,7 @@ class DirPanel extends React.Component {
path={this.props.path}
repoID={this.props.repoID}
showShareBtn={this.props.showShareBtn}
direntList={this.props.direntList}
onAddFile={this.props.onAddFile}
onAddFolder={this.props.onAddFolder}
onUploadFile={this.onUploadFile}

View File

@@ -11,6 +11,7 @@ import Lightbox from 'react-image-lightbox';
import 'react-image-lightbox/style.css';
import '../../css/tip-for-new-md.css';
import toaster from '../toast';
const propTypes = {
path: PropTypes.string.isRequired,
@@ -61,6 +62,19 @@ class DirentListView extends React.Component {
this.setState({isItemFreezed: false});
}
onItemRename = (dirent, newName) => {
let isDuplicated = this.props.direntList.some(item => {
return item.name === newName;
});
if (isDuplicated) {
let errMessage = gettext('The name {name} is already occupied, please choose another name.');
errMessage = errMessage.replace('{name}', Utils.HTMLescape(newName));
toaster.danger(errMessage);
return false;
}
this.props.onItemRename(dirent, newName);
}
onItemRenameToggle = () => {
this.onFreezedItem();
}
@@ -238,11 +252,12 @@ class DirentListView extends React.Component {
repoID={this.props.repoID}
currentRepoInfo={this.props.currentRepoInfo}
isRepoOwner={this.props.isRepoOwner}
direntList={this.props.direntList}
onItemClick={this.props.onItemClick}
onItemRenameToggle={this.onItemRenameToggle}
onItemSelected={this.props.onItemSelected}
onItemDelete={this.props.onItemDelete}
onItemRename={this.props.onItemRename}
onItemRename={this.onItemRename}
onItemMove={this.props.onItemMove}
onItemCopy={this.props.onItemCopy}
updateDirent={this.props.updateDirent}

View File

@@ -20,6 +20,7 @@ const propTypes = {
onUploadFolder: PropTypes.func.isRequired,
isDraft: PropTypes.bool,
hasDraft: PropTypes.bool,
direntList: PropTypes.array.isRequired,
};
class DirOperationToolbar extends React.Component {
@@ -167,6 +168,14 @@ class DirOperationToolbar extends React.Component {
this.props.goDraftPage();
}
checkDuplicatedName = (newName) => {
let direntList = this.props.direntList;
let isDuplicated = direntList.some(object => {
return object.name === newName;
});
return isDuplicated;
}
render() {
let { path, isViewFile } = this.props;
let itemType = isViewFile ? 'file' : 'dir';
@@ -220,8 +229,9 @@ class DirOperationToolbar extends React.Component {
parentPath={this.props.path}
fileType={this.state.fileType}
onAddFile={this.onAddFile}
checkDuplicatedName={this.checkDuplicatedName}
addFileCancel={this.onCreateFileToggle}
/>
/>
</ModalPortal>
)}
{this.state.isCreateFolderDialogShow && (
@@ -229,6 +239,7 @@ class DirOperationToolbar extends React.Component {
<CreateFolder
parentPath={this.props.path}
onAddFolder={this.onAddFolder}
checkDuplicatedName={this.checkDuplicatedName}
addFolderCancel={this.onCreateFolderToggle}
/>
</ModalPortal>

View File

@@ -1,6 +1,7 @@
import { Utils } from '../../utils/utils';
import Tree from './tree';
import TreeNode from './tree-node';
import Dirent from '../../models/dirent';
class TreeHelper {
@@ -74,11 +75,12 @@ class TreeHelper {
return treeCopy;
}
moveNodeByPath(tree, nodePath, destPath) {
moveNodeByPath(tree, nodePath, destPath, nodeName) {
let treeCopy = tree.clone();
let node = treeCopy.getNodeByPath(nodePath);
let destNode = treeCopy.getNodeByPath(destPath);
if (destNode && node) { // node has loaded
if (destNode && node) { // node has loaded
node.object.name = nodeName; // need not update path
treeCopy.moveNode(node, destNode);
}
if (!destNode && node){
@@ -94,7 +96,7 @@ class TreeHelper {
nodePaths.forEach(nodePath => {
let node = treeCopy.getNodeByPath(nodePath);
treeCopy.moveNode(node, destNode);
})
});
} else {
nodePaths.forEach(nodePath=> {
let node = treeCopy.getNodeByPath(nodePath);
@@ -104,12 +106,13 @@ class TreeHelper {
return treeCopy;
}
copyNodeByPath(tree, nodePath, destPath) {
copyNodeByPath(tree, nodePath, destPath, nodeName) {
let treeCopy = tree.clone();
let node = treeCopy.getNodeByPath(nodePath);
node = node.clone(); // need a dup
let destNode = treeCopy.getNodeByPath(destPath);
let treeNode = treeCopy.getNodeByPath(nodePath);
if (destNode) {
let node = treeNode.clone(); // need a dup
node.object.name = nodeName; // need not update path
treeCopy.copyNode(node, destNode);
}
return treeCopy;
@@ -129,7 +132,7 @@ class TreeHelper {
buildTree() {
let tree = new Tree();
let object = {name: '/'};
let object = new Dirent({name: '/'});
let root = new TreeNode({object, isLoaded: false, isExpanded: true});
tree.setRoot(root);
return tree;

View File

@@ -2,7 +2,7 @@ class TreeNode {
constructor({ path, object, isLoaded, isPreload, isExpanded, parentNode }) {
this.path = path || object.name, // The default setting is the object name, which is set to a relative path when the father is set.
this.object = object;
this.object = object.clone();
this.isLoaded = isLoaded || false;
this.isPreload = isPreload || false;
this.isExpanded = isExpanded || false;
@@ -13,7 +13,7 @@ class TreeNode {
clone() {
let treeNode = new TreeNode({
path: this.path,
object: this.object,
object: this.object.clone(),
isLoaded: this.isLoaded,
isPreload: this.isPreload,
isExpanded: this.isExpanded,
@@ -102,7 +102,7 @@ class TreeNode {
const treeNode = {
path: this.path,
object: this.object,
object: this.object.clone(),
isLoaded: this.isLoaded,
isPreload: this.isPreload,
isExpanded: this.isExpanded,
@@ -115,6 +115,7 @@ class TreeNode {
static deserializefromJson(json) {
let { path, object, isLoaded, isPreload, isExpanded, parentNode, children = [] } = json;
object = object.clone();
const treeNode = new TreeNode({
path,