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:
12
frontend/package-lock.json
generated
12
frontend/package-lock.json
generated
@@ -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",
|
||||||
|
@@ -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>
|
||||||
|
@@ -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}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@@ -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>
|
||||||
|
@@ -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>
|
||||||
|
Reference in New Issue
Block a user