mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-19 10:26:17 +00:00
Add department transfer function to the administrator interface (#6014)
* Add the function of transferring departments in the administrator interface * fix admin get all departments * update * Update departments.py * update * update * add department repo transfer * Update groups.py * update --------- Co-authored-by: 孙永强 <11704063+s-yongqiang@user.noreply.gitee.com> Co-authored-by: r350178982 <32759763+r350178982@users.noreply.github.com>
This commit is contained in:
@@ -1,19 +1,34 @@
|
||||
import React from 'react';
|
||||
import React, {Fragment} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
|
||||
import {
|
||||
Button,
|
||||
Modal,
|
||||
ModalHeader,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
Nav,
|
||||
NavItem,
|
||||
NavLink,
|
||||
TabContent,
|
||||
TabPane
|
||||
} from 'reactstrap';
|
||||
import makeAnimated from 'react-select/animated';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
import { gettext, isPro } from '../../utils/constants';
|
||||
import {gettext, isPro, orgID} from '../../utils/constants';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import toaster from '../toast';
|
||||
import UserSelect from '../user-select';
|
||||
import { SeahubSelect } from '../common/select';
|
||||
import '../../css/transfer-dialog.css';
|
||||
|
||||
const propTypes = {
|
||||
itemName: PropTypes.string.isRequired,
|
||||
toggleDialog: PropTypes.func.isRequired,
|
||||
submit: PropTypes.func.isRequired,
|
||||
canTransferToDept: PropTypes.bool
|
||||
canTransferToDept: PropTypes.bool,
|
||||
isOrgAdmin: PropTypes.bool,
|
||||
isSysAdmin: PropTypes.bool,
|
||||
|
||||
};
|
||||
|
||||
class TransferDialog extends React.Component {
|
||||
@@ -23,23 +38,54 @@ class TransferDialog extends React.Component {
|
||||
selectedOption: null,
|
||||
errorMsg: [],
|
||||
transferToUser: true,
|
||||
transferToGroup: false,
|
||||
activeTab: 'transUser'
|
||||
};
|
||||
this.options = [];
|
||||
}
|
||||
|
||||
handleSelectChange = (option) => {
|
||||
this.setState({selectedOption: option});
|
||||
this.setState({ selectedOption: option });
|
||||
};
|
||||
|
||||
submit = () => {
|
||||
let user = this.state.selectedOption;
|
||||
this.props.submit(user);
|
||||
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
if (isPro) {
|
||||
if (this.props.isOrgAdmin) {
|
||||
seafileAPI.orgAdminListDepartments(orgID).then((res) => {
|
||||
for (let i = 0; i < res.data.length; i++) {
|
||||
let obj = {};
|
||||
obj.value = res.data[i].name;
|
||||
obj.email = res.data[i].email;
|
||||
obj.label = res.data[i].name;
|
||||
this.options.push(obj);
|
||||
}
|
||||
}).catch(error => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
toaster.danger(errMessage);
|
||||
});
|
||||
}
|
||||
else if (this.props.isSysAdmin) {
|
||||
seafileAPI.sysAdminListDepartments().then((res) => {
|
||||
for (let i = 0; i < res.data.length; i++) {
|
||||
let obj = {};
|
||||
obj.value = res.data[i].name;
|
||||
obj.email = res.data[i].email;
|
||||
obj.label = res.data[i].name;
|
||||
this.options.push(obj);
|
||||
}
|
||||
}).catch(error => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
toaster.danger(errMessage);
|
||||
});
|
||||
}
|
||||
else{
|
||||
seafileAPI.listDepartments().then((res) => {
|
||||
for (let i = 0 ; i < res.data.length; i++) {
|
||||
for (let i = 0; i < res.data.length; i++) {
|
||||
let obj = {};
|
||||
obj.value = res.data[i].name;
|
||||
obj.email = res.data[i].email;
|
||||
@@ -56,49 +102,85 @@ class TransferDialog extends React.Component {
|
||||
onClick = () => {
|
||||
this.setState({
|
||||
transferToUser: !this.state.transferToUser,
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
toggle = (tab) => {
|
||||
if (this.state.activeTab !== tab) {
|
||||
this.setState({ activeTab: tab });
|
||||
}
|
||||
};
|
||||
|
||||
renderTransContent = () => {
|
||||
let activeTab = this.state.activeTab;
|
||||
let canTransferToDept = true;
|
||||
if (this.props.canTransferToDept != undefined) {
|
||||
canTransferToDept = this.props.canTransferToDept;
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="transfer-dialog-side">
|
||||
<Nav pills>
|
||||
<NavItem role="tab" aria-selected={activeTab === 'transUser'} aria-controls="transfer-user-panel">
|
||||
<NavLink className={activeTab === 'transUser' ? 'active' : ''} onClick={(this.toggle.bind(this, 'transUser'))} tabIndex="0" onKeyDown={this.onTabKeyDown}>
|
||||
{gettext('Transfer to user')}
|
||||
</NavLink>
|
||||
</NavItem>
|
||||
{isPro &&
|
||||
<NavItem role="tab" aria-selected={activeTab === 'transDepart'} aria-controls="transfer-depart-panel">
|
||||
<NavLink className={activeTab === 'transDepart' ? 'active' : ''} onClick={this.toggle.bind(this, 'transDepart')} tabIndex="0" onKeyDown={this.onTabKeyDown}>
|
||||
{gettext('Transfer to department')}
|
||||
</NavLink>
|
||||
</NavItem>}
|
||||
</Nav>
|
||||
</div>
|
||||
<div className="transfer-dialog-main">
|
||||
<TabContent activeTab={this.state.activeTab}>
|
||||
<Fragment>
|
||||
<TabPane tabId="transUser" role="tabpanel" id="transfer-user-panel">
|
||||
<UserSelect
|
||||
ref="userSelect"
|
||||
isMulti={false}
|
||||
className="reviewer-select"
|
||||
placeholder={gettext('Select a user')}
|
||||
onSelectChange={this.handleSelectChange}
|
||||
/>
|
||||
</TabPane>
|
||||
{isPro && canTransferToDept &&
|
||||
<TabPane tabId="transDepart" role="tabpanel" id="transfer-depart-panel">
|
||||
<SeahubSelect
|
||||
isClearable
|
||||
maxMenuHeight={200}
|
||||
hideSelectedOptions={true}
|
||||
components={makeAnimated()}
|
||||
placeholder={gettext('Select a department')}
|
||||
options={this.options}
|
||||
onChange={this.handleSelectChange}
|
||||
value={this.state.selectedOption}
|
||||
/>
|
||||
</TabPane>}
|
||||
</Fragment>
|
||||
</TabContent>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
render() {
|
||||
|
||||
|
||||
const { itemName: repoName } = this.props;
|
||||
let title = gettext('Transfer Library {library_name}');
|
||||
title = title.replace('{library_name}', '<span class="op-target text-truncate mx-1">' + Utils.HTMLescape(repoName) + '</span>');
|
||||
|
||||
|
||||
return (
|
||||
<Modal isOpen={true} toggle={this.props.toggleDialog}>
|
||||
<Modal isOpen={true} style={{maxWidth: '720px'}} toggle={this.props.toggleDialog} className="transfer-dialog">
|
||||
<ModalHeader toggle={this.props.toggleDialog}>
|
||||
<span dangerouslySetInnerHTML={{__html: title}} className="d-flex mw-100"></span>
|
||||
<span dangerouslySetInnerHTML={{ __html: title }} className="d-flex mw-100"></span>
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
{this.state.transferToUser ?
|
||||
<UserSelect
|
||||
ref="userSelect"
|
||||
isMulti={false}
|
||||
className="reviewer-select"
|
||||
placeholder={gettext('Select a user')}
|
||||
onSelectChange={this.handleSelectChange}
|
||||
/> :
|
||||
<SeahubSelect
|
||||
isClearable
|
||||
maxMenuHeight={200}
|
||||
hideSelectedOptions={true}
|
||||
components={makeAnimated()}
|
||||
placeholder={gettext('Select a department')}
|
||||
options={this.options}
|
||||
onChange={this.handleSelectChange}
|
||||
value={this.state.selectedOption}
|
||||
/>
|
||||
}
|
||||
{isPro && canTransferToDept &&
|
||||
<span role="button" tabIndex="0" className="action-link" onClick={this.onClick} onKeyDown={Utils.onKeyDown}>{this.state.transferToUser ?
|
||||
gettext('Transfer to department'): gettext('Transfer to user')}
|
||||
</span>
|
||||
}
|
||||
<ModalBody className="transfer-dialog-content" role="tablist">
|
||||
{this.renderTransContent()}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="secondary" onClick={this.props.toggleDialog}>{gettext('Cancel')}</Button>
|
||||
|
52
frontend/src/css/transfer-dialog.css
Normal file
52
frontend/src/css/transfer-dialog.css
Normal file
@@ -0,0 +1,52 @@
|
||||
.transfer-dialog .transfer-dialog-content {
|
||||
padding: 0;
|
||||
min-height: 22.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.transfer-dialog .transfer-dialog-content {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.transfer-dialog-content .transfer-dialog-side {
|
||||
flex-basis: 29%;
|
||||
padding: 1rem;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.transfer-dialog .nav .nav-item .nav-link {
|
||||
padding: 0.3125rem 0.25rem;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.transfer-dialog-content .transfer-dialog-side {
|
||||
padding: 12px 8px;
|
||||
border: 0;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
.transfer-dialog-side .nav {
|
||||
flex-direction: column;
|
||||
}
|
||||
.transfer-dialog-side .nav-pills .nav-item .nav-link {
|
||||
width: 100%;
|
||||
padding: 0.3125rem 0.5rem;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.transfer-dialog-content .transfer-dialog-main {
|
||||
display: flex;
|
||||
flex-basis: 78%;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.transfer-dialog-content .transfer-dialog-main .tab-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.transfer-dialog-content .transfer-dialog-main .tab-pane {
|
||||
height: 100%;
|
||||
}
|
@@ -200,7 +200,8 @@ class RepoItem extends React.Component {
|
||||
highlight: false,
|
||||
showMenu: false,
|
||||
isItemMenuShow: false,
|
||||
isTransferDialogShow: false
|
||||
isTransferDialogShow: false,
|
||||
orgAdmin: true
|
||||
};
|
||||
}
|
||||
|
||||
@@ -291,7 +292,7 @@ class RepoItem extends React.Component {
|
||||
render() {
|
||||
let { repo } = this.props;
|
||||
|
||||
let isOperationMenuShow = this.state.showMenu && !repo.isDepartmentRepo;
|
||||
let isOperationMenuShow = this.state.showMenu;
|
||||
return (
|
||||
<Fragment>
|
||||
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
||||
@@ -326,6 +327,7 @@ class RepoItem extends React.Component {
|
||||
itemName={repo.repoName}
|
||||
submit={this.onTransferRepo}
|
||||
toggleDialog={this.toggleTransfer}
|
||||
isOrgAdmin={true}
|
||||
/>
|
||||
</ModalPortal>
|
||||
)}
|
||||
|
@@ -280,6 +280,12 @@ class Item extends Component {
|
||||
getOperations = () => {
|
||||
const { repo } = this.props;
|
||||
let operations = ['Delete', 'Transfer'];
|
||||
const index = repo.owner_email.indexOf('@seafile_group');
|
||||
let isGroupOwnedRepo = index != -1;
|
||||
if (isGroupOwnedRepo) {
|
||||
operations = ['Transfer'];
|
||||
return operations;
|
||||
}
|
||||
if (!repo.encrypted) {
|
||||
operations.push('Share');
|
||||
}
|
||||
@@ -319,7 +325,7 @@ class Item extends Component {
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
{(!isGroupOwnedRepo && isOpIconShown) &&
|
||||
{(isOpIconShown) &&
|
||||
<OpMenu
|
||||
operations={this.getOperations()}
|
||||
translateOperations={this.translateOperations}
|
||||
@@ -359,8 +365,8 @@ class Item extends Component {
|
||||
<TransferDialog
|
||||
itemName={repo.name}
|
||||
submit={this.onTransferRepo}
|
||||
canTransferToDept={false}
|
||||
toggleDialog={this.toggleTransferDialog}
|
||||
isSysAdmin={true}
|
||||
/>
|
||||
</ModalPortal>
|
||||
}
|
||||
|
Reference in New Issue
Block a user