1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-02 15:38:15 +00:00

Group repo rename (#2926)

* add rename for group repo

* freezed item when renaming

* add mobile rename handler
This commit is contained in:
杨顺强
2019-02-11 15:22:42 +08:00
committed by Daniel Pan
parent 1a78c81309
commit 4288db826e
5 changed files with 112 additions and 27 deletions

View File

@@ -5286,7 +5286,7 @@
}, },
"git-up": { "git-up": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "http://registry.npmjs.org/git-up/-/git-up-1.2.1.tgz", "resolved": "https://registry.npmjs.org/git-up/-/git-up-1.2.1.tgz",
"integrity": "sha1-JkSAoAax2EJhrB/gmjpRacV+oZ0=", "integrity": "sha1-JkSAoAax2EJhrB/gmjpRacV+oZ0=",
"requires": { "requires": {
"is-ssh": "^1.0.0", "is-ssh": "^1.0.0",
@@ -5295,7 +5295,7 @@
}, },
"git-url-parse": { "git-url-parse": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "http://registry.npmjs.org/git-url-parse/-/git-url-parse-5.0.1.tgz", "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-5.0.1.tgz",
"integrity": "sha1-/j15xnRq4FBIz6UIyB553du6OEM=", "integrity": "sha1-/j15xnRq4FBIz6UIyB553du6OEM=",
"requires": { "requires": {
"git-up": "^1.0.0" "git-up": "^1.0.0"
@@ -7858,7 +7858,7 @@
}, },
"node-status-codes": { "node-status-codes": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "http://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz", "resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz",
"integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=" "integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8="
}, },
"noop6": { "noop6": {
@@ -8165,7 +8165,7 @@
}, },
"package.json": { "package.json": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "http://registry.npmjs.org/package.json/-/package.json-2.0.1.tgz", "resolved": "https://registry.npmjs.org/package.json/-/package.json-2.0.1.tgz",
"integrity": "sha1-+IYFnSpJ7QduZIg2ldc7K0bSHW0=", "integrity": "sha1-+IYFnSpJ7QduZIg2ldc7K0bSHW0=",
"requires": { "requires": {
"git-package-json": "^1.4.0", "git-package-json": "^1.4.0",
@@ -8175,7 +8175,7 @@
"dependencies": { "dependencies": {
"got": { "got": {
"version": "5.7.1", "version": "5.7.1",
"resolved": "http://registry.npmjs.org/got/-/got-5.7.1.tgz", "resolved": "https://registry.npmjs.org/got/-/got-5.7.1.tgz",
"integrity": "sha1-X4FjWmHkplifGAVp6k44FoClHzU=", "integrity": "sha1-X4FjWmHkplifGAVp6k44FoClHzU=",
"requires": { "requires": {
"create-error-class": "^3.0.1", "create-error-class": "^3.0.1",
@@ -8197,7 +8197,7 @@
}, },
"package-json": { "package-json": {
"version": "2.4.0", "version": "2.4.0",
"resolved": "http://registry.npmjs.org/package-json/-/package-json-2.4.0.tgz", "resolved": "https://registry.npmjs.org/package-json/-/package-json-2.4.0.tgz",
"integrity": "sha1-DRW9Z9HLvduyyiIv8u24a8sxqLs=", "integrity": "sha1-DRW9Z9HLvduyyiIv8u24a8sxqLs=",
"requires": { "requires": {
"got": "^5.0.0", "got": "^5.0.0",

View File

@@ -7,6 +7,7 @@ import { Utils } from '../../utils/utils';
import { gettext, siteRoot, isPro, username, folderPermEnabled, isSystemStaff } from '../../utils/constants'; import { gettext, siteRoot, isPro, username, folderPermEnabled, isSystemStaff } from '../../utils/constants';
import ModalPotal from '../../components/modal-portal'; import ModalPotal from '../../components/modal-portal';
import ShareDialog from '../../components/dialog/share-dialog'; import ShareDialog from '../../components/dialog/share-dialog';
import Rename from '../rename';
const propTypes = { const propTypes = {
currentGroup: PropTypes.object, currentGroup: PropTypes.object,
@@ -14,8 +15,10 @@ const propTypes = {
repo: PropTypes.object.isRequired, repo: PropTypes.object.isRequired,
isItemFreezed: PropTypes.bool.isRequired, isItemFreezed: PropTypes.bool.isRequired,
onFreezedItem: PropTypes.func.isRequired, onFreezedItem: PropTypes.func.isRequired,
onUnfreezedItem: PropTypes.func.isRequired,
onItemUnshare: PropTypes.func.isRequired, onItemUnshare: PropTypes.func.isRequired,
onItmeDetails: PropTypes.func, onItmeDetails: PropTypes.func,
onItemRename: PropTypes.func,
}; };
class SharedRepoListItem extends React.Component { class SharedRepoListItem extends React.Component {
@@ -27,6 +30,7 @@ class SharedRepoListItem extends React.Component {
isOperationShow: false, isOperationShow: false,
isItemMenuShow: false, isItemMenuShow: false,
isShowSharedDialog: false, isShowSharedDialog: false,
isRenaming: false,
}; };
this.isDeparementOnwerGroupMember = false; this.isDeparementOnwerGroupMember = false;
} }
@@ -59,23 +63,30 @@ class SharedRepoListItem extends React.Component {
} }
clickOperationMenuToggle = (e) => { clickOperationMenuToggle = (e) => {
e.preventDefault(); this.toggleOperationMenu(e);
this.toggleOperationMenu();
} }
toggleOperationMenu = () => { toggleOperationMenu = (e) => {
if (this.props.isItemFreezed) { let dataset = e.target ? e.target.dataset : null;
this.setState({ if (dataset && dataset.toggle && dataset.toggle === 'Rename') {
highlight: false, this.setState({isItemMenuShow: !this.state.isItemMenuShow});
isOperationShow: false, return;
isItemMenuShow: !this.state.isItemMenuShow
});
} else {
this.setState({
isItemMenuShow: !this.state.isItemMenuShow
});
} }
this.props.onFreezedItem();
this.setState(
{isItemMenuShow: !this.state.isItemMenuShow},
() => {
if (this.state.isItemMenuShow) {
this.props.onFreezedItem();
} else {
this.props.onUnfreezedItem();
this.setState({
highlight: false,
isOperationShow: false,
});
}
}
);
} }
getRepoComputeParams = () => { getRepoComputeParams = () => {
@@ -92,7 +103,7 @@ class SharedRepoListItem extends React.Component {
let operation = e.target.dataset.toggle; let operation = e.target.dataset.toggle;
switch(operation) { switch(operation) {
case 'Rename': case 'Rename':
this.onItemRename(); this.onItemRenameToggle();
break; break;
case 'Folder Permission': case 'Folder Permission':
this.onItemPermisionChanged(); this.onItemPermisionChanged();
@@ -111,8 +122,22 @@ class SharedRepoListItem extends React.Component {
} }
} }
onItemRename = () => { onItemRenameToggle = () => {
// todo this.props.onFreezedItem();
this.setState({
isRenaming: !this.state.isRenaming,
isOperationShow: !this.state.isOperationShow
});
}
onRenameConfirm = (name) => {
this.props.onItemRename(this.props.repo, name);
this.onRenameCancel();
}
onRenameCancel = () => {
this.props.onUnfreezedItem();
this.setState({isRenaming: !this.state.isRenaming});
} }
onItemPermisionChanged = () => { onItemPermisionChanged = () => {
@@ -308,7 +333,12 @@ class SharedRepoListItem extends React.Component {
<Fragment> <Fragment>
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseOver={this.onMouseOver} onMouseLeave={this.onMouseLeave}> <tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseOver={this.onMouseOver} onMouseLeave={this.onMouseLeave}>
<td><img src={iconUrl} title={repo.iconTitle} alt={iconTitle} width="24" /></td> <td><img src={iconUrl} title={repo.iconTitle} alt={iconTitle} width="24" /></td>
<td><Link to={libPath}>{repo.repo_name}</Link></td> <td>
{this.state.isRenaming ?
<Rename name={repo.repo_name} onRenameConfirm={this.onRenameConfirm} onRenameCancel={this.onRenameCancel}/> :
<Link to={libPath}>{repo.repo_name}</Link>
}
</td>
<td>{this.state.isOperationShow && this.generatorPCMenu()}</td> <td>{this.state.isOperationShow && this.generatorPCMenu()}</td>
<td>{repo.size}</td> <td>{repo.size}</td>
<td title={moment(repo.last_modified).format('llll')}>{moment(repo.last_modified).fromNow()}</td> <td title={moment(repo.last_modified).format('llll')}>{moment(repo.last_modified).fromNow()}</td>
@@ -343,7 +373,11 @@ class SharedRepoListItem extends React.Component {
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseOver={this.onMouseOver} onMouseLeave={this.onMouseLeave}> <tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseOver={this.onMouseOver} onMouseLeave={this.onMouseLeave}>
<td><img src={iconUrl} title={iconTitle} width="24" alt={iconTitle}/></td> <td><img src={iconUrl} title={iconTitle} width="24" alt={iconTitle}/></td>
<td> <td>
<Link to={libPath}>{repo.repo_name}</Link><br /> {this.state.isRenaming ?
<Rename name={repo.repo_name} onRenameConfirm={this.onRenameConfirm} onRenameCancel={this.onRenameCancel} /> :
<Link to={libPath}>{repo.repo_name}</Link>
}
<br />
<span className="item-meta-info" title={repo.owner_contact_email}>{repo.owner_name}</span> <span className="item-meta-info" title={repo.owner_contact_email}>{repo.owner_name}</span>
<span className="item-meta-info">{repo.size}</span> <span className="item-meta-info">{repo.size}</span>
<span className="item-meta-info" title={moment(repo.last_modified).format('llll')}>{moment(repo.last_modified).fromNow()}</span> <span className="item-meta-info" title={moment(repo.last_modified).format('llll')}>{moment(repo.last_modified).fromNow()}</span>

View File

@@ -1,7 +1,9 @@
import React, {Fragment} from 'react'; import React, {Fragment} from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { gettext } from '../../utils/constants'; import { gettext } from '../../utils/constants';
import { Utils } from '../../utils/utils';
import SharedRepoListItem from './shared-repo-list-item'; import SharedRepoListItem from './shared-repo-list-item';
import toaster from '../toast';
const propTypes = { const propTypes = {
libraryType: PropTypes.string, libraryType: PropTypes.string,
@@ -14,6 +16,7 @@ const propTypes = {
onItemUnshare: PropTypes.func.isRequired, onItemUnshare: PropTypes.func.isRequired,
onItemDelete: PropTypes.func.isRequired, onItemDelete: PropTypes.func.isRequired,
onItemDetails: PropTypes.func, onItemDetails: PropTypes.func,
onItemRename: PropTypes.func,
}; };
class SharedRepoListView extends React.Component { class SharedRepoListView extends React.Component {
@@ -48,9 +51,24 @@ class SharedRepoListView extends React.Component {
} }
onFreezedItem = () => { onFreezedItem = () => {
this.setState({ this.setState({isItemFreezed: true});
isItemFreezed: !this.state.isItemFreezed, }
onUnfreezedItem = () => {
this.setState({isItemFreezed: false});
}
onItemRename = (repo, newName) => {
let isDuplicated = this.props.repoList.some(item => {
return item.name === newName;
}); });
if (isDuplicated) {
let errMessage = gettext('The name "{name}" is already taken. Please choose a different name.');
errMessage = errMessage.replace('{name}', Utils.HTMLescape(newName));
toaster.danger(errMessage);
return false;
}
this.props.onItemRename(repo, newName);
} }
renderRepoListView = () => { renderRepoListView = () => {
@@ -65,9 +83,11 @@ class SharedRepoListView extends React.Component {
currentGroup={this.props.currentGroup} currentGroup={this.props.currentGroup}
isItemFreezed={this.state.isItemFreezed} isItemFreezed={this.state.isItemFreezed}
onFreezedItem={this.onFreezedItem} onFreezedItem={this.onFreezedItem}
onUnfreezedItem={this.onUnfreezedItem}
onItemUnshare={this.props.onItemUnshare} onItemUnshare={this.props.onItemUnshare}
onItemDelete={this.props.onItemDelete} onItemDelete={this.props.onItemDelete}
onItemDetails={this.props.onItemDetails} onItemDetails={this.props.onItemDetails}
onItemRename={this.props.onItemRename}
/> />
); );
})} })}

View File

@@ -239,6 +239,20 @@ class GroupView extends React.Component {
}); });
} }
onItemRename = (repo, newName) => {
seafileAPI.renameGroupOwnedLibrary(this.props.groupID, repo.repo_id, newName).then(res => {
let repoList = this.state.repoList.map(item => {
if (item.repo_id === repo.repo_id) {
item.repo_name = newName;
}
return item;
});
this.setState({repoList: repoList});
}).catch(() => {
// todo
});
}
onTabNavClick = (tabName) => { onTabNavClick = (tabName) => {
this.props.onTabNavClick(tabName); this.props.onTabNavClick(tabName);
} }
@@ -436,6 +450,7 @@ class GroupView extends React.Component {
onItemUnshare={this.onItemUnshare} onItemUnshare={this.onItemUnshare}
onItemDelete={this.onItemDelete} onItemDelete={this.onItemDelete}
onItemDetails={this.onItemDetails} onItemDetails={this.onItemDetails}
onItemRename={this.onItemRename}
/> />
} }
</div> </div>

View File

@@ -58,6 +58,21 @@ class RepoListViewPanel extends React.Component {
}); });
} }
onItemRename = (repo, newName) => {
let group = this.props.group;
seafileAPI.renameGroupOwnedLibrary(group.id, repo.repo_id, newName).then(res => {
let repoList = this.state.repoList.map(item => {
if (item.repo_id === repo.repo_id) {
item.repo_name = newName;
}
return item;
});
this.setState({repoList: repoList});
}).catch(() => {
// todo
});
}
render() { render() {
let group = this.props.group; let group = this.props.group;
const emptyTip = <p className="group-item-empty-tip">{gettext('No libraries')}</p>; const emptyTip = <p className="group-item-empty-tip">{gettext('No libraries')}</p>;
@@ -76,6 +91,7 @@ class RepoListViewPanel extends React.Component {
onItemUnshare={this.onItemUnshare} onItemUnshare={this.onItemUnshare}
onItemDelete={this.onItemDelete} onItemDelete={this.onItemDelete}
onItemDetails={this.props.onItemDetails} onItemDetails={this.props.onItemDetails}
onItemRename={this.onItemRename}
/> />
} }
</div> </div>