mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-16 14:08:12 +00:00
Merge branch '12.0'
This commit is contained in:
commit
344cd865b2
@ -157,19 +157,6 @@ class App extends Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onGroupChanged = (groupID) => {
|
|
||||||
setTimeout(function () {
|
|
||||||
let url;
|
|
||||||
if (groupID) {
|
|
||||||
url = siteRoot + 'group/' + groupID + '/';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
url = siteRoot + 'libraries/';
|
|
||||||
}
|
|
||||||
window.location = url.toString();
|
|
||||||
}, 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
tabItemClick = (tabName, groupID) => {
|
tabItemClick = (tabName, groupID) => {
|
||||||
let pathPrefix = [];
|
let pathPrefix = [];
|
||||||
if (groupID || this.dirViewPanels.indexOf(tabName) > -1) {
|
if (groupID || this.dirViewPanels.indexOf(tabName) > -1) {
|
||||||
@ -343,7 +330,7 @@ class App extends Component {
|
|||||||
<InvitationsView path={siteRoot + 'invitations/'} />
|
<InvitationsView path={siteRoot + 'invitations/'} />
|
||||||
<FilesActivities path={siteRoot + 'dashboard'} />
|
<FilesActivities path={siteRoot + 'dashboard'} />
|
||||||
<MyFileActivities path={siteRoot + 'my-activities'} />
|
<MyFileActivities path={siteRoot + 'my-activities'} />
|
||||||
<GroupView path={siteRoot + 'group/:groupID'} onGroupChanged={this.onGroupChanged} />
|
<GroupView path={siteRoot + 'group/:groupID'} />
|
||||||
<LinkedDevices path={siteRoot + 'linked-devices'} />
|
<LinkedDevices path={siteRoot + 'linked-devices'} />
|
||||||
<ShareAdminLibraries path={siteRoot + 'share-admin-libs'} />
|
<ShareAdminLibraries path={siteRoot + 'share-admin-libs'} />
|
||||||
<ShareAdminFolders path={siteRoot + 'share-admin-folders'} />
|
<ShareAdminFolders path={siteRoot + 'share-admin-folders'} />
|
||||||
|
@ -9,14 +9,11 @@ import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
|||||||
|
|
||||||
class DismissGroupDialog extends React.Component {
|
class DismissGroupDialog extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
dismissGroup = () => {
|
dismissGroup = () => {
|
||||||
let that = this;
|
const { groupID } = this.props;
|
||||||
seafileAPI.deleteGroup(this.props.groupID).then((res) => {
|
seafileAPI.deleteGroup(groupID).then((res) => {
|
||||||
that.props.onGroupChanged();
|
this.props.onGroupDeleted();
|
||||||
|
toaster.success(gettext('Group deleted'));
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
toaster.danger(errMessage);
|
toaster.danger(errMessage);
|
||||||
@ -25,13 +22,13 @@ class DismissGroupDialog extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={this.props.showDismissGroupDialog} toggle={this.props.toggleDismissGroupDialog}>
|
<Modal isOpen={true} toggle={this.props.toggleDialog}>
|
||||||
<SeahubModalHeader>{gettext('Delete Group')}</SeahubModalHeader>
|
<SeahubModalHeader toggle={this.props.toggleDialog}>{gettext('Delete Group')}</SeahubModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<span>{gettext('Really want to delete this group?')}</span>
|
<span>{gettext('Really want to delete this group?')}</span>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button color="secondary" onClick={this.props.toggleDismissGroupDialog}>{gettext('Cancel')}</Button>
|
<Button color="secondary" onClick={this.props.toggleDialog}>{gettext('Cancel')}</Button>
|
||||||
<Button color="primary" onClick={this.dismissGroup}>{gettext('Delete')}</Button>
|
<Button color="primary" onClick={this.dismissGroup}>{gettext('Delete')}</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</Modal>
|
</Modal>
|
||||||
@ -40,11 +37,9 @@ class DismissGroupDialog extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DismissGroupDialogPropTypes = {
|
const DismissGroupDialogPropTypes = {
|
||||||
showDismissGroupDialog: PropTypes.bool.isRequired,
|
groupID: PropTypes.number.isRequired,
|
||||||
toggleDismissGroupDialog: PropTypes.func.isRequired,
|
toggleDialog: PropTypes.func.isRequired,
|
||||||
loadGroup: PropTypes.func.isRequired,
|
onGroupDeleted: PropTypes.func.isRequired
|
||||||
groupID: PropTypes.string,
|
|
||||||
onGroupChanged: PropTypes.func.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DismissGroupDialog.propTypes = DismissGroupDialogPropTypes;
|
DismissGroupDialog.propTypes = DismissGroupDialogPropTypes;
|
||||||
|
@ -9,7 +9,7 @@ import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
|||||||
import Loading from '../loading';
|
import Loading from '../loading';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
groupID: PropTypes.string.isRequired,
|
groupID: PropTypes.number.isRequired,
|
||||||
toggleDialog: PropTypes.func.isRequired
|
toggleDialog: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import { gettext, siteRoot, groupImportMembersExtraMsg } from '../../utils/const
|
|||||||
import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
toggleImportMembersDialog: PropTypes.func.isRequired,
|
toggleDialog: PropTypes.func.isRequired,
|
||||||
importMembersInBatch: PropTypes.func.isRequired,
|
importMembersInBatch: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ class ImportMembersDialog extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggle = () => {
|
toggle = () => {
|
||||||
this.props.toggleImportMembersDialog();
|
this.props.toggleDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
openFileInput = () => {
|
openFileInput = () => {
|
||||||
@ -49,9 +49,8 @@ class ImportMembersDialog extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<Modal isOpen={true} toggle={this.toggle}>
|
<Modal isOpen={true} toggle={this.toggle}>
|
||||||
<SeahubModalHeader toggle={this.toggle}>{gettext('Import members from a .xlsx file')}</SeahubModalHeader>
|
<SeahubModalHeader toggle={this.toggle}>{gettext('Import members from a .xlsx file')}</SeahubModalHeader>
|
||||||
|
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<p>{groupImportMembersExtraMsg}</p>
|
{groupImportMembersExtraMsg && <p>{groupImportMembersExtraMsg}</p>}
|
||||||
<p><a className="text-secondary small" href={`${siteRoot}api/v2.1/group-members-import-example/`}>{gettext('Download an example file')}</a></p>
|
<p><a className="text-secondary small" href={`${siteRoot}api/v2.1/group-members-import-example/`}>{gettext('Download an example file')}</a></p>
|
||||||
<button className="btn btn-outline-primary" onClick={this.openFileInput}>{gettext('Upload file')}</button>
|
<button className="btn btn-outline-primary" onClick={this.openFileInput}>{gettext('Upload file')}</button>
|
||||||
<input className="d-none" type="file" onChange={this.uploadFile} ref={this.fileInputRef} />
|
<input className="d-none" type="file" onChange={this.uploadFile} ref={this.fileInputRef} />
|
||||||
|
@ -9,13 +9,10 @@ import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
|||||||
|
|
||||||
class LeaveGroupDialog extends React.Component {
|
class LeaveGroupDialog extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
leaveGroup = () => {
|
leaveGroup = () => {
|
||||||
seafileAPI.quitGroup(this.props.groupID, username).then((res) => {
|
const { groupID } = this.props;
|
||||||
this.props.onGroupChanged();
|
seafileAPI.quitGroup(groupID, username).then((res) => {
|
||||||
|
this.props.onLeavingGroup();
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
toaster.danger(errMessage);
|
toaster.danger(errMessage);
|
||||||
@ -24,13 +21,13 @@ class LeaveGroupDialog extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={true} toggle={this.props.toggleLeaveGroupDialog}>
|
<Modal isOpen={true} toggle={this.props.toggleDialog}>
|
||||||
<SeahubModalHeader toggle={this.props.toggleLeaveGroupDialog}>{gettext('Leave Group')}</SeahubModalHeader>
|
<SeahubModalHeader toggle={this.props.toggleDialog}>{gettext('Leave Group')}</SeahubModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<p>{gettext('Really want to leave this group?')}</p>
|
<p>{gettext('Really want to leave this group?')}</p>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button color="secondary" onClick={this.props.toggleLeaveGroupDialog}>{gettext('Cancel')}</Button>
|
<Button color="secondary" onClick={this.props.toggleDialog}>{gettext('Cancel')}</Button>
|
||||||
<Button color="primary" onClick={this.leaveGroup}>{gettext('Leave')}</Button>
|
<Button color="primary" onClick={this.leaveGroup}>{gettext('Leave')}</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</Modal>
|
</Modal>
|
||||||
@ -39,9 +36,9 @@ class LeaveGroupDialog extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const LeaveGroupDialogPropTypes = {
|
const LeaveGroupDialogPropTypes = {
|
||||||
toggleLeaveGroupDialog: PropTypes.func.isRequired,
|
groupID: PropTypes.number.isRequired,
|
||||||
groupID: PropTypes.string,
|
onLeavingGroup: PropTypes.func.isRequired,
|
||||||
onGroupChanged: PropTypes.func.isRequired,
|
toggleDialog: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
LeaveGroupDialog.propTypes = LeaveGroupDialogPropTypes;
|
LeaveGroupDialog.propTypes = LeaveGroupDialogPropTypes;
|
||||||
|
@ -8,7 +8,7 @@ import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
|||||||
import '../../css/manage-members-dialog.css';
|
import '../../css/manage-members-dialog.css';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
groupID: PropTypes.string,
|
groupID: PropTypes.number.isRequired,
|
||||||
isOwner: PropTypes.bool.isRequired,
|
isOwner: PropTypes.bool.isRequired,
|
||||||
toggleManageMembersDialog: PropTypes.func,
|
toggleManageMembersDialog: PropTypes.func,
|
||||||
toggleDepartmentDetailDialog: PropTypes.func,
|
toggleDepartmentDetailDialog: PropTypes.func,
|
||||||
|
@ -9,7 +9,7 @@ import toaster from '../toast';
|
|||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
toggle: PropTypes.func.isRequired,
|
toggle: PropTypes.func.isRequired,
|
||||||
groupID: PropTypes.number.isRequired,
|
group: PropTypes.object.isRequired,
|
||||||
onSetQuota: PropTypes.func.isRequired,
|
onSetQuota: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ class SetGroupQuotaDialog extends React.Component {
|
|||||||
if ((quota.length && myReg.test(quota)) || quota == -2) {
|
if ((quota.length && myReg.test(quota)) || quota == -2) {
|
||||||
this.setState({ errMessage: '' });
|
this.setState({ errMessage: '' });
|
||||||
let newQuota = this.state.quota == -2 ? this.state.quota : this.state.quota * 1000000;
|
let newQuota = this.state.quota == -2 ? this.state.quota : this.state.quota * 1000000;
|
||||||
orgAdminAPI.orgAdminSetGroupQuota(orgID, this.props.groupID, newQuota).then((res) => {
|
orgAdminAPI.orgAdminSetGroupQuota(orgID, this.props.group.id, newQuota).then((res) => {
|
||||||
this.props.toggle();
|
this.props.toggle();
|
||||||
this.props.onSetQuota(res.data);
|
this.props.onSetQuota(res.data);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@ -55,10 +55,15 @@ class SetGroupQuotaDialog extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const group = this.props.group;
|
||||||
|
const oldQuota = Utils.bytesToSize(group.quota);
|
||||||
|
const message = gettext('The current quota for {group_name} is {quota}').replace('{group_name}', group.name).replace('{quota}', oldQuota);
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={true} toggle={this.props.toggle} autoFocus={false}>
|
<Modal isOpen={true} toggle={this.props.toggle} autoFocus={false}>
|
||||||
<SeahubModalHeader toggle={this.props.toggle}>{gettext('Set Quota')}</SeahubModalHeader>
|
<SeahubModalHeader toggle={this.props.toggle}>{gettext('Set Quota')}</SeahubModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
|
<p>{message}</p>
|
||||||
|
<p>{gettext('Please enter a new quota')}</p>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<Input
|
<Input
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDown}
|
||||||
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|||||||
import { gettext } from '../../utils/constants';
|
import { gettext } from '../../utils/constants';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import { Modal, ModalBody, ModalFooter, Input, Button } from 'reactstrap';
|
import { Modal, ModalBody, ModalFooter, Input, Label, Button } from 'reactstrap';
|
||||||
import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
||||||
import toaster from '../toast';
|
import toaster from '../toast';
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ class RenameGroupDialog extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
newGroupName: this.props.currentGroupName,
|
newGroupName: this.props.groupName,
|
||||||
isSubmitBtnActive: false,
|
isSubmitBtnActive: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -30,48 +30,42 @@ class RenameGroupDialog extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
renameGroup = () => {
|
handleSubmit = () => {
|
||||||
let name = this.state.newGroupName.trim();
|
const { groupID } = this.props;
|
||||||
if (name) {
|
const { newGroupName } = this.state;
|
||||||
let that = this;
|
seafileAPI.renameGroup(groupID, newGroupName.trim()).then((res) => {
|
||||||
seafileAPI.renameGroup(this.props.groupID, name).then((res) => {
|
const { name } = res.data;
|
||||||
that.props.loadGroup(this.props.groupID);
|
this.props.onGroupNameChanged(name);
|
||||||
that.props.onGroupChanged(res.data.id);
|
}).catch(error => {
|
||||||
}).catch(error => {
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
toaster.danger(errMessage);
|
||||||
toaster.danger(errMessage);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
newGroupName: '',
|
|
||||||
});
|
});
|
||||||
this.props.toggleRenameGroupDialog();
|
this.props.toggleDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
handleKeyDown = (event) => {
|
handleKeyDown = (event) => {
|
||||||
if (event.keyCode === 13) {
|
if (event.keyCode === 13) {
|
||||||
this.renameGroup();
|
this.handleSubmit();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={this.props.showRenameGroupDialog} toggle={this.props.toggleRenameGroupDialog}>
|
<Modal isOpen={true} toggle={this.props.toggleDialog}>
|
||||||
<SeahubModalHeader>{gettext('Rename Group')}</SeahubModalHeader>
|
<SeahubModalHeader toggle={this.props.toggleDialog}>{gettext('Rename Group')}</SeahubModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<label htmlFor="newGroupName">{gettext('Rename group to')}</label>
|
<Label for="group-name">{gettext('Rename group to')}</Label>
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
id="newGroupName"
|
id="group-name"
|
||||||
name="new-group-name"
|
|
||||||
value={this.state.newGroupName}
|
value={this.state.newGroupName}
|
||||||
onChange={this.handleGroupNameChange}
|
onChange={this.handleGroupNameChange}
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDown}
|
||||||
/>
|
/>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button color="secondary" onClick={this.props.toggleRenameGroupDialog}>{gettext('Cancel')}</Button>
|
<Button color="secondary" onClick={this.props.toggleDialog}>{gettext('Cancel')}</Button>
|
||||||
<Button color="primary" onClick={this.renameGroup} disabled={!this.state.isSubmitBtnActive}>{gettext('Submit')}</Button>
|
<Button color="primary" onClick={this.handleSubmit} disabled={!this.state.isSubmitBtnActive}>{gettext('Submit')}</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
@ -79,12 +73,10 @@ class RenameGroupDialog extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const RenameGroupDialogPropTypes = {
|
const RenameGroupDialogPropTypes = {
|
||||||
showRenameGroupDialog: PropTypes.bool.isRequired,
|
toggleDialog: PropTypes.func.isRequired,
|
||||||
toggleRenameGroupDialog: PropTypes.func.isRequired,
|
groupID: PropTypes.number,
|
||||||
loadGroup: PropTypes.func.isRequired,
|
onGroupNameChanged: PropTypes.func.isRequired,
|
||||||
groupID: PropTypes.string,
|
groupName: PropTypes.string.isRequired,
|
||||||
onGroupChanged: PropTypes.func.isRequired,
|
|
||||||
currentGroupName: PropTypes.string.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
RenameGroupDialog.propTypes = RenameGroupDialogPropTypes;
|
RenameGroupDialog.propTypes = RenameGroupDialogPropTypes;
|
||||||
|
@ -9,7 +9,7 @@ import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
|||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
toggle: PropTypes.func.isRequired,
|
toggle: PropTypes.func.isRequired,
|
||||||
groupID: PropTypes.number.isRequired,
|
group: PropTypes.object.isRequired,
|
||||||
onSetQuota: PropTypes.func.isRequired,
|
onSetQuota: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ class SetGroupQuotaDialog extends React.Component {
|
|||||||
if ((quota.length && numberReg.test(quota)) || quota == -2) {
|
if ((quota.length && numberReg.test(quota)) || quota == -2) {
|
||||||
this.setState({ errMessage: '' });
|
this.setState({ errMessage: '' });
|
||||||
let newQuota = this.state.quota == -2 ? this.state.quota : this.state.quota * 1000000;
|
let newQuota = this.state.quota == -2 ? this.state.quota : this.state.quota * 1000000;
|
||||||
systemAdminAPI.sysAdminUpdateDepartmentQuota(this.props.groupID, newQuota).then((res) => {
|
systemAdminAPI.sysAdminUpdateDepartmentQuota(this.props.group.id, newQuota).then((res) => {
|
||||||
this.props.toggle();
|
this.props.toggle();
|
||||||
this.props.onSetQuota(res.data);
|
this.props.onSetQuota(res.data);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@ -55,10 +55,15 @@ class SetGroupQuotaDialog extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const group = this.props.group;
|
||||||
|
const oldQuota = Utils.bytesToSize(group.quota);
|
||||||
|
const message = gettext('The current quota for {group_name} is {quota}').replace('{group_name}', group.name).replace('{quota}', oldQuota);
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={true} toggle={this.props.toggle} autoFocus={false}>
|
<Modal isOpen={true} toggle={this.props.toggle} autoFocus={false}>
|
||||||
<SeahubModalHeader toggle={this.props.toggle}>{gettext('Set Quota')}</SeahubModalHeader>
|
<SeahubModalHeader toggle={this.props.toggle}>{gettext('Set Quota')}</SeahubModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
|
<p>{message}</p>
|
||||||
|
<p>{gettext('Please enter a new quota')}</p>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<Input
|
<Input
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDown}
|
||||||
|
@ -11,9 +11,9 @@ import toaster from '../toast';
|
|||||||
import '../../css/transfer-group-dialog.css';
|
import '../../css/transfer-group-dialog.css';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
groupID: PropTypes.string,
|
groupID: PropTypes.number.isRequired,
|
||||||
toggleTransferGroupDialog: PropTypes.func.isRequired,
|
onGroupTransfered: PropTypes.func.isRequired,
|
||||||
onGroupChanged: PropTypes.func.isRequired
|
toggleDialog: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
class TransferGroupDialog extends React.Component {
|
class TransferGroupDialog extends React.Component {
|
||||||
@ -21,19 +21,14 @@ class TransferGroupDialog extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
selectedOption: null,
|
selectedOption: null
|
||||||
errMessage: '',
|
|
||||||
};
|
};
|
||||||
this.options = [];
|
|
||||||
this.userSelect = React.createRef();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSelectChange = (option) => {
|
handleSelectChange = (option) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedOption: option,
|
selectedOption: option
|
||||||
errMessage: '',
|
|
||||||
});
|
});
|
||||||
this.options = [];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
transferGroup = () => {
|
transferGroup = () => {
|
||||||
@ -42,19 +37,21 @@ class TransferGroupDialog extends React.Component {
|
|||||||
if (selectedOption && selectedOption[0]) {
|
if (selectedOption && selectedOption[0]) {
|
||||||
email = selectedOption[0].email;
|
email = selectedOption[0].email;
|
||||||
}
|
}
|
||||||
if (email) {
|
if (!email) {
|
||||||
seafileAPI.transferGroup(this.props.groupID, email).then((res) => {
|
return false;
|
||||||
this.props.toggleTransferGroupDialog();
|
|
||||||
toaster.success(gettext('Group has been transfered'));
|
|
||||||
}).catch((error) => {
|
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
|
||||||
this.setState({ errMessage: errMessage });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
seafileAPI.transferGroup(this.props.groupID, email).then((res) => {
|
||||||
|
toaster.success(gettext('Group has been transfered'));
|
||||||
|
this.props.onGroupTransfered(res.data);
|
||||||
|
this.props.toggleDialog();
|
||||||
|
}).catch((error) => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
toggle = () => {
|
toggle = () => {
|
||||||
this.props.toggleTransferGroupDialog();
|
this.props.toggleDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -69,7 +66,6 @@ class TransferGroupDialog extends React.Component {
|
|||||||
placeholder={gettext('Please enter 1 or more character')}
|
placeholder={gettext('Please enter 1 or more character')}
|
||||||
onSelectChange={this.handleSelectChange}
|
onSelectChange={this.handleSelectChange}
|
||||||
/>
|
/>
|
||||||
<div className="error">{this.state.errMessage}</div>
|
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button color="secondary" onClick={this.toggle}>{gettext('Close')}</Button>
|
<Button color="secondary" onClick={this.toggle}>{gettext('Close')}</Button>
|
||||||
|
@ -10,7 +10,7 @@ import OpIcon from './op-icon';
|
|||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
groupMembers: PropTypes.array.isRequired,
|
groupMembers: PropTypes.array.isRequired,
|
||||||
groupID: PropTypes.string,
|
groupID: PropTypes.number.isRequired,
|
||||||
isOwner: PropTypes.bool.isRequired,
|
isOwner: PropTypes.bool.isRequired,
|
||||||
isItemFreezed: PropTypes.bool.isRequired,
|
isItemFreezed: PropTypes.bool.isRequired,
|
||||||
toggleItemFreezed: PropTypes.func.isRequired,
|
toggleItemFreezed: PropTypes.func.isRequired,
|
||||||
@ -61,7 +61,7 @@ const MemberPropTypes = {
|
|||||||
changeMember: PropTypes.func.isRequired,
|
changeMember: PropTypes.func.isRequired,
|
||||||
deleteMember: PropTypes.func.isRequired,
|
deleteMember: PropTypes.func.isRequired,
|
||||||
toggleItemFreezed: PropTypes.func.isRequired,
|
toggleItemFreezed: PropTypes.func.isRequired,
|
||||||
groupID: PropTypes.string,
|
groupID: PropTypes.number.isRequired,
|
||||||
isOwner: PropTypes.bool.isRequired,
|
isOwner: PropTypes.bool.isRequired,
|
||||||
isItemFreezed: PropTypes.bool.isRequired
|
isItemFreezed: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,7 @@ import GroupMembers from './group-members';
|
|||||||
const propTypes = {
|
const propTypes = {
|
||||||
toggleManageMembersDialog: PropTypes.func,
|
toggleManageMembersDialog: PropTypes.func,
|
||||||
toggleDepartmentDetailDialog: PropTypes.func,
|
toggleDepartmentDetailDialog: PropTypes.func,
|
||||||
groupID: PropTypes.string,
|
groupID: PropTypes.number.isRequired,
|
||||||
isOwner: PropTypes.bool.isRequired
|
isOwner: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,8 +73,8 @@ class Selector extends Component {
|
|||||||
<div onClick={this.onToggleClick}>
|
<div onClick={this.onToggleClick}>
|
||||||
{customSelectorToggle ? customSelectorToggle : (
|
{customSelectorToggle ? customSelectorToggle : (
|
||||||
<span className="cur-option">
|
<span className="cur-option">
|
||||||
{currentSelectedOption.text}
|
{currentSelectedOption ? currentSelectedOption.text : ''}
|
||||||
{isDropdownToggleShown && <i className="sf3-font sf3-font-down ml-2 toggle-icon"></i>}
|
{isDropdownToggleShown && <i className="sf3-font sf3-font-down ml-1 toggle-icon"></i>}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { gettext, siteRoot, username } from '../../utils/constants';
|
import { gettext, siteRoot } from '../../utils/constants';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import toaster from '../../components/toast';
|
import toaster from '../../components/toast';
|
||||||
import SharedRepoListView from '../../components/shared-repo-list-view/shared-repo-list-view';
|
import SharedRepoListView from '../../components/shared-repo-list-view/shared-repo-list-view';
|
||||||
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
|
|
||||||
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
|
|
||||||
import Repo from '../../models/repo';
|
|
||||||
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
||||||
|
import GroupOperationMenu from './group-op-menu';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
inAllLibs: PropTypes.bool,
|
inAllLibs: PropTypes.bool,
|
||||||
@ -17,21 +15,18 @@ const propTypes = {
|
|||||||
onMonitorRepo: PropTypes.func,
|
onMonitorRepo: PropTypes.func,
|
||||||
renameRelatedGroupsRepos: PropTypes.func,
|
renameRelatedGroupsRepos: PropTypes.func,
|
||||||
deleteRelatedGroupsRepos: PropTypes.func,
|
deleteRelatedGroupsRepos: PropTypes.func,
|
||||||
insertRepoIntoGroup: PropTypes.func,
|
addRepoToGroup: PropTypes.func,
|
||||||
unshareRepoToGroup: PropTypes.func,
|
unshareRepoToGroup: PropTypes.func,
|
||||||
onTransferRepo: PropTypes.func.isRequired,
|
onTransferRepo: PropTypes.func.isRequired,
|
||||||
|
onGroupNameChanged: PropTypes.func.isRequired,
|
||||||
|
onGroupTransfered: PropTypes.func.isRequired,
|
||||||
|
onGroupDeleted: PropTypes.func.isRequired,
|
||||||
|
onLeavingGroup: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class GroupItem extends React.Component {
|
class GroupItem extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
isCreateRepoDialogOpen: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onItemUnshare = (repo) => {
|
onItemUnshare = (repo) => {
|
||||||
const { group } = this.props;
|
const { group } = this.props;
|
||||||
const { id: group_id } = group;
|
const { id: group_id } = group;
|
||||||
@ -61,53 +56,45 @@ class GroupItem extends React.Component {
|
|||||||
this.props.onMonitorRepo(repo, monitored);
|
this.props.onMonitorRepo(repo, monitored);
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleCreateRepoDialog = () => {
|
addNewRepo = (newRepo) => {
|
||||||
this.setState({
|
|
||||||
isCreateRepoDialogOpen: !this.state.isCreateRepoDialogOpen
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onCreateRepo = (repo) => {
|
|
||||||
const { group } = this.props;
|
const { group } = this.props;
|
||||||
const { id: group_id } = group;
|
const { id: group_id } = group;
|
||||||
seafileAPI.createGroupOwnedLibrary(group_id, repo).then(res => {
|
this.props.addRepoToGroup({ repo: newRepo, group_id });
|
||||||
let object = {
|
};
|
||||||
repo_id: res.data.id,
|
|
||||||
repo_name: res.data.name,
|
onGroupNameChanged = (newName) => {
|
||||||
owner_name: res.data.group_name,
|
const { group } = this.props;
|
||||||
owner_email: res.data.owner,
|
this.props.onGroupNameChanged(newName, group.id);
|
||||||
permission: res.data.permission,
|
};
|
||||||
mtime: res.data.mtime,
|
|
||||||
size: res.data.size,
|
onGroupDeleted = () => {
|
||||||
encrypted: res.data.encrypted,
|
const { group } = this.props;
|
||||||
};
|
this.props.onGroupDeleted(group.id);
|
||||||
const newRepo = new Repo(object);
|
};
|
||||||
this.props.insertRepoIntoGroup({ repo: newRepo, group_id });
|
|
||||||
}).catch(error => {
|
onLeavingGroup = () => {
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
const { group } = this.props;
|
||||||
toaster.danger(errMessage);
|
this.props.onLeavingGroup(group.id);
|
||||||
});
|
|
||||||
this.toggleCreateRepoDialog();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { inAllLibs = false, group, currentViewMode = LIST_MODE } = this.props;
|
const { inAllLibs = false, group, currentViewMode = LIST_MODE } = this.props;
|
||||||
const { parent_group_id, admins } = group;
|
|
||||||
const emptyTip = <p className={`libraries-empty-tip-in-${currentViewMode}-mode`}>{gettext('No libraries')}</p>;
|
const emptyTip = <p className={`libraries-empty-tip-in-${currentViewMode}-mode`}>{gettext('No libraries')}</p>;
|
||||||
|
|
||||||
const isDeptAdmin = parent_group_id != 0 && admins.indexOf(username) > -1;
|
|
||||||
return (
|
return (
|
||||||
<div className="pb-3">
|
<div className="pb-3">
|
||||||
<div className={`d-flex justify-content-between mt-3 py-1 ${currentViewMode == LIST_MODE ? 'sf-border-bottom' : ''}`}>
|
<div className={`d-flex justify-content-between mt-3 py-1 ${currentViewMode == LIST_MODE ? 'sf-border-bottom' : ''}`}>
|
||||||
<h4 className="sf-heading m-0 d-flex align-items-center">
|
<h4 className="sf-heading m-0 d-flex align-items-center">
|
||||||
<span className={`${group.parent_group_id == 0 ? 'sf3-font-group' : 'sf3-font-department'} sf3-font nav-icon`} aria-hidden="true"></span>
|
<span className={`${group.parent_group_id == 0 ? 'sf3-font-group' : 'sf3-font-department'} sf3-font nav-icon`} aria-hidden="true"></span>
|
||||||
<a href={`${siteRoot}group/${group.id}/`} title={group.name} className="ellipsis">{group.name}</a>
|
<a href={`${siteRoot}group/${group.id}/`} title={group.name} className="ellipsis">{group.name}</a>
|
||||||
{isDeptAdmin &&
|
<GroupOperationMenu
|
||||||
<SingleDropdownToolbar
|
group={group}
|
||||||
withPlusIcon={true}
|
addNewRepo={this.addNewRepo}
|
||||||
opList={[{ 'text': gettext('New Library'), 'onClick': this.toggleCreateRepoDialog }]}
|
onGroupNameChanged={this.onGroupNameChanged}
|
||||||
/>
|
onGroupTransfered={this.props.onGroupTransfered}
|
||||||
}
|
onGroupDeleted={this.onGroupDeleted}
|
||||||
|
onLeavingGroup={this.onLeavingGroup}
|
||||||
|
/>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
{group.repos.length === 0 ?
|
{group.repos.length === 0 ?
|
||||||
@ -127,13 +114,6 @@ class GroupItem extends React.Component {
|
|||||||
currentViewMode={currentViewMode}
|
currentViewMode={currentViewMode}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
{this.state.isCreateRepoDialogOpen &&
|
|
||||||
<CreateRepoDialog
|
|
||||||
onCreateToggle={this.toggleCreateRepoDialog}
|
|
||||||
onCreateRepo={this.onCreateRepo}
|
|
||||||
libraryType='department'
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
273
frontend/src/pages/groups/group-op-menu.js
Normal file
273
frontend/src/pages/groups/group-op-menu.js
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { gettext, username, canAddRepo } from '../../utils/constants';
|
||||||
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
import toaster from '../../components/toast';
|
||||||
|
import { Repo } from '../../models';
|
||||||
|
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
|
||||||
|
import GroupMembersDialog from '../../components/dialog/group-members-dialog';
|
||||||
|
import DismissGroupDialog from '../../components/dialog/dismiss-group-dialog';
|
||||||
|
import RenameGroupDialog from '../../components/dialog/rename-group-dialog';
|
||||||
|
import TransferGroupDialog from '../../components/dialog/transfer-group-dialog';
|
||||||
|
import ImportMembersDialog from '../../components/dialog/import-members-dialog';
|
||||||
|
import ManageMembersDialog from '../../components/dialog/manage-members-dialog';
|
||||||
|
import DepartmentDetailDialog from '../../components/dialog/department-detail-dialog';
|
||||||
|
import LeaveGroupDialog from '../../components/dialog/leave-group-dialog';
|
||||||
|
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
|
||||||
|
|
||||||
|
import '../../css/group-view.css';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
group: PropTypes.object.isRequired,
|
||||||
|
addNewRepo: PropTypes.func.isRequired,
|
||||||
|
onGroupNameChanged: PropTypes.func.isRequired,
|
||||||
|
onGroupTransfered: PropTypes.func.isRequired,
|
||||||
|
onGroupDeleted: PropTypes.func.isRequired,
|
||||||
|
onLeavingGroup: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
class GroupOperationMenu extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isCreateRepoDialogOpen: false,
|
||||||
|
isShowDepartmentDetailDialog: false,
|
||||||
|
isRenameGroupDialogOpen: false,
|
||||||
|
isDeleteGroupDialogOpen: false,
|
||||||
|
isTransferGroupDialogOpen: false,
|
||||||
|
isImportMembersDialogOpen: false,
|
||||||
|
isManageMembersDialogOpen: false,
|
||||||
|
isLeaveGroupDialogOpen: false,
|
||||||
|
isMembersDialogOpen: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onCreateRepoToggle = () => {
|
||||||
|
this.setState({ isCreateRepoDialogOpen: !this.state.isCreateRepoDialogOpen });
|
||||||
|
};
|
||||||
|
|
||||||
|
onCreateRepo = (repo, groupType) => {
|
||||||
|
const { group } = this.props;
|
||||||
|
const groupId = group.id;
|
||||||
|
if (groupType && groupType === 'department') {
|
||||||
|
seafileAPI.createGroupOwnedLibrary(groupId, repo).then(res => {
|
||||||
|
let object = {
|
||||||
|
repo_id: res.data.id,
|
||||||
|
repo_name: res.data.name,
|
||||||
|
owner_name: res.data.group_name,
|
||||||
|
owner_email: res.data.owner,
|
||||||
|
permission: res.data.permission,
|
||||||
|
mtime: res.data.mtime,
|
||||||
|
size: res.data.size,
|
||||||
|
encrypted: res.data.encrypted,
|
||||||
|
};
|
||||||
|
const repo = new Repo(object);
|
||||||
|
this.props.addNewRepo(repo);
|
||||||
|
}).catch(error => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
seafileAPI.createGroupRepo(groupId, repo).then(res => {
|
||||||
|
const repo = new Repo(res.data);
|
||||||
|
this.props.addNewRepo(repo);
|
||||||
|
}).catch(error => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.onCreateRepoToggle();
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleDeleteGroupDialog = () => {
|
||||||
|
this.setState({
|
||||||
|
isDeleteGroupDialogOpen: !this.state.isDeleteGroupDialogOpen,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleRenameGroupDialog = () => {
|
||||||
|
this.setState({
|
||||||
|
isRenameGroupDialogOpen: !this.state.isRenameGroupDialogOpen,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleTransferGroupDialog = () => {
|
||||||
|
this.setState({
|
||||||
|
isTransferGroupDialogOpen: !this.state.isTransferGroupDialogOpen,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleImportMembersDialog = () => {
|
||||||
|
this.setState({
|
||||||
|
isImportMembersDialogOpen: !this.state.isImportMembersDialogOpen
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
importMembersInBatch = (file) => {
|
||||||
|
toaster.notify(gettext('It may take some time, please wait.'), { 'id': 'importing-members' });
|
||||||
|
const { group } = this.props;
|
||||||
|
seafileAPI.importGroupMembersViaFile(group.id, file).then((res) => {
|
||||||
|
res.data.success.forEach(item => {
|
||||||
|
toaster.success(gettext('Successfully imported {user_placeholder}').replace('{user_placeholder}', `${item.contact_email}`), { 'id': 'importing-members' });
|
||||||
|
});
|
||||||
|
res.data.failed.forEach(item => {
|
||||||
|
toaster.danger(`${item.email}: ${item.error_msg}`, { 'id': 'importing-members' });
|
||||||
|
});
|
||||||
|
}).catch((error) => {
|
||||||
|
let errMsg = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMsg);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleManageMembersDialog = () => {
|
||||||
|
this.setState({
|
||||||
|
isManageMembersDialogOpen: !this.state.isManageMembersDialogOpen,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleLeaveGroupDialog = () => {
|
||||||
|
this.setState({
|
||||||
|
isLeaveGroupDialogOpen: !this.state.isLeaveGroupDialogOpen,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleMembersDialog = () => {
|
||||||
|
this.setState({
|
||||||
|
isMembersDialogOpen: !this.state.isMembersDialogOpen
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleDepartmentDetailDialog = () => {
|
||||||
|
this.setState({
|
||||||
|
isShowDepartmentDetailDialog: !this.state.isShowDepartmentDetailDialog
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getOpList = () => {
|
||||||
|
const { group } = this.props;
|
||||||
|
const isDepartment = group.parent_group_id !== 0;
|
||||||
|
const isStaff = group.admins.indexOf(username) > -1;
|
||||||
|
const isOwner = group.owner === username;
|
||||||
|
const opList = [];
|
||||||
|
if ((!isDepartment && canAddRepo) ||
|
||||||
|
(isDepartment && isStaff)) {
|
||||||
|
this.newLibraryEnabled = true;
|
||||||
|
opList.push({ 'text': gettext('New Library'), 'onClick': this.onCreateRepoToggle }, 'Divider');
|
||||||
|
}
|
||||||
|
opList.push({ 'text': gettext('Members'), 'onClick': this.toggleMembersDialog });
|
||||||
|
if (isStaff || isOwner) {
|
||||||
|
opList.push({ 'text': gettext('Import members'), 'onClick': this.toggleImportMembersDialog });
|
||||||
|
opList.push({ 'text': gettext('Manage members'), 'onClick': this.toggleManageMembersDialog });
|
||||||
|
opList.push('Divider');
|
||||||
|
opList.push({ 'text': gettext('Rename'), 'onClick': this.toggleRenameGroupDialog });
|
||||||
|
if (isOwner) {
|
||||||
|
opList.push({ 'text': gettext('Transfer'), 'onClick': this.toggleTransferGroupDialog });
|
||||||
|
}
|
||||||
|
if (isOwner) {
|
||||||
|
opList.push({ 'text': gettext('Delete group'), 'onClick': this.toggleDeleteGroupDialog });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isOwner && !isDepartment) {
|
||||||
|
opList.push({ 'text': gettext('Leave group'), 'onClick': this.toggleLeaveGroupDialog });
|
||||||
|
}
|
||||||
|
|
||||||
|
return opList;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
isCreateRepoDialogOpen,
|
||||||
|
isMembersDialogOpen
|
||||||
|
} = this.state;
|
||||||
|
const { group } = this.props;
|
||||||
|
const { id: groupID, parent_group_id, owner } = group;
|
||||||
|
const isDepartment = parent_group_id !== 0;
|
||||||
|
const isOwner = owner === username;
|
||||||
|
|
||||||
|
const opList = this.getOpList();
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{group && (
|
||||||
|
<SingleDropdownToolbar
|
||||||
|
withPlusIcon={this.newLibraryEnabled}
|
||||||
|
opList={opList}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{isCreateRepoDialogOpen &&
|
||||||
|
<CreateRepoDialog
|
||||||
|
onCreateToggle={this.onCreateRepoToggle}
|
||||||
|
onCreateRepo={this.onCreateRepo}
|
||||||
|
libraryType={isDepartment ? 'department' : 'group'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{isMembersDialogOpen &&
|
||||||
|
<GroupMembersDialog
|
||||||
|
groupID={groupID}
|
||||||
|
toggleDialog={this.toggleMembersDialog}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{this.state.isRenameGroupDialogOpen &&
|
||||||
|
<RenameGroupDialog
|
||||||
|
groupID={groupID}
|
||||||
|
groupName={group.name}
|
||||||
|
onGroupNameChanged={this.props.onGroupNameChanged}
|
||||||
|
toggleDialog={this.toggleRenameGroupDialog}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{this.state.isDeleteGroupDialogOpen &&
|
||||||
|
<DismissGroupDialog
|
||||||
|
groupID={groupID}
|
||||||
|
onGroupDeleted={this.props.onGroupDeleted}
|
||||||
|
toggleDialog={this.toggleDeleteGroupDialog}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{this.state.isTransferGroupDialogOpen &&
|
||||||
|
<TransferGroupDialog
|
||||||
|
groupID={groupID}
|
||||||
|
onGroupTransfered={this.props.onGroupTransfered}
|
||||||
|
toggleDialog={this.toggleTransferGroupDialog}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{this.state.isImportMembersDialogOpen &&
|
||||||
|
<ImportMembersDialog
|
||||||
|
importMembersInBatch={this.importMembersInBatch}
|
||||||
|
toggleDialog={this.toggleImportMembersDialog}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{this.state.isManageMembersDialogOpen &&
|
||||||
|
<ManageMembersDialog
|
||||||
|
groupID={groupID}
|
||||||
|
isOwner={isOwner}
|
||||||
|
toggleManageMembersDialog={this.toggleManageMembersDialog}
|
||||||
|
toggleDepartmentDetailDialog={this.toggleDepartmentDetailDialog}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{this.state.isShowDepartmentDetailDialog &&
|
||||||
|
<DepartmentDetailDialog
|
||||||
|
usedFor='add_group_member'
|
||||||
|
toggleDepartmentDetailDialog={this.toggleDepartmentDetailDialog}
|
||||||
|
toggleManageMembersDialog={this.toggleManageMembersDialog}
|
||||||
|
groupID={groupID}
|
||||||
|
isOwner={isOwner}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{this.state.isLeaveGroupDialogOpen &&
|
||||||
|
<LeaveGroupDialog
|
||||||
|
groupID={groupID}
|
||||||
|
toggleDialog={this.toggleLeaveGroupDialog}
|
||||||
|
onLeavingGroup={this.props.onLeavingGroup}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupOperationMenu.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default GroupOperationMenu;
|
@ -2,36 +2,25 @@ import React, { Fragment } from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import cookie from 'react-cookies';
|
import cookie from 'react-cookies';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { gettext, username, canAddRepo, isMultiTenancy } from '../../utils/constants';
|
import { navigate } from '@gatsbyjs/reach-router';
|
||||||
|
import { gettext, siteRoot, username } from '../../utils/constants';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import Loading from '../../components/loading';
|
import Loading from '../../components/loading';
|
||||||
import EmptyTip from '../../components/empty-tip';
|
import EmptyTip from '../../components/empty-tip';
|
||||||
import ModalPortal from '../../components/modal-portal';
|
|
||||||
import toaster from '../../components/toast';
|
import toaster from '../../components/toast';
|
||||||
import { Group, Repo } from '../../models';
|
import { Group, Repo } from '../../models';
|
||||||
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
|
|
||||||
import GroupMembersDialog from '../../components/dialog/group-members-dialog';
|
|
||||||
import DismissGroupDialog from '../../components/dialog/dismiss-group-dialog';
|
|
||||||
import RenameGroupDialog from '../../components/dialog/rename-group-dialog';
|
|
||||||
import TransferGroupDialog from '../../components/dialog/transfer-group-dialog';
|
|
||||||
import ImportMembersDialog from '../../components/dialog/import-members-dialog';
|
|
||||||
import ManageMembersDialog from '../../components/dialog/manage-members-dialog';
|
|
||||||
import DepartmentDetailDialog from '../../components/dialog/department-detail-dialog';
|
|
||||||
import LeaveGroupDialog from '../../components/dialog/leave-group-dialog';
|
|
||||||
import SharedRepoListView from '../../components/shared-repo-list-view/shared-repo-list-view';
|
import SharedRepoListView from '../../components/shared-repo-list-view/shared-repo-list-view';
|
||||||
import SortOptionsDialog from '../../components/dialog/sort-options';
|
import SortOptionsDialog from '../../components/dialog/sort-options';
|
||||||
import GroupInviteMembersDialog from '../../components/dialog/group-invite-members-dialog';
|
|
||||||
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
|
|
||||||
import ViewModes from '../../components/view-modes';
|
import ViewModes from '../../components/view-modes';
|
||||||
import ReposSortMenu from '../../components/sort-menu';
|
import ReposSortMenu from '../../components/sort-menu';
|
||||||
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
||||||
|
import GroupOperationMenu from './group-op-menu';
|
||||||
|
|
||||||
import '../../css/group-view.css';
|
import '../../css/group-view.css';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
onGroupChanged: PropTypes.func.isRequired,
|
groupID: PropTypes.string
|
||||||
groupID: PropTypes.string,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class GroupView extends React.Component {
|
class GroupView extends React.Component {
|
||||||
@ -44,9 +33,6 @@ class GroupView extends React.Component {
|
|||||||
errMessage: '',
|
errMessage: '',
|
||||||
emptyTip: null,
|
emptyTip: null,
|
||||||
currentGroup: null,
|
currentGroup: null,
|
||||||
currentRepo: null,
|
|
||||||
isStaff: false,
|
|
||||||
isOwner: false,
|
|
||||||
currentViewMode: localStorage.getItem('sf_repo_list_view_mode') || LIST_MODE,
|
currentViewMode: localStorage.getItem('sf_repo_list_view_mode') || LIST_MODE,
|
||||||
sortBy: cookie.load('seafile-repo-dir-sort-by') || 'name', // 'name' or 'time' or 'size'
|
sortBy: cookie.load('seafile-repo-dir-sort-by') || 'name', // 'name' or 'time' or 'size'
|
||||||
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
|
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
|
||||||
@ -55,20 +41,7 @@ class GroupView extends React.Component {
|
|||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
perPage: 300,
|
perPage: 300,
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
libraryType: 'group',
|
|
||||||
isCreateRepoDialogShow: false,
|
|
||||||
isDepartmentGroup: false,
|
isDepartmentGroup: false,
|
||||||
isShowDepartmentDetailDialog: false,
|
|
||||||
showGroupDropdown: false,
|
|
||||||
showGroupMembersPopover: false,
|
|
||||||
showRenameGroupDialog: false,
|
|
||||||
showDismissGroupDialog: false,
|
|
||||||
showTransferGroupDialog: false,
|
|
||||||
showImportMembersDialog: false,
|
|
||||||
showManageMembersDialog: false,
|
|
||||||
showInviteMembersDialog: false,
|
|
||||||
isLeaveGroupDialogOpen: false,
|
|
||||||
isMembersDialogOpen: false
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,9 +61,7 @@ class GroupView extends React.Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
emptyTip: this.getEmptyTip(currentGroup),
|
emptyTip: this.getEmptyTip(currentGroup),
|
||||||
currentGroup,
|
currentGroup,
|
||||||
isStaff: currentGroup.admins.indexOf(username) > -1, // for item operations
|
|
||||||
isDepartmentGroup: currentGroup.parent_group_id !== 0,
|
isDepartmentGroup: currentGroup.parent_group_id !== 0,
|
||||||
isOwner: currentGroup.owner === username,
|
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
repoList: [] // empty it for the current group
|
repoList: [] // empty it for the current group
|
||||||
}, () => {
|
}, () => {
|
||||||
@ -162,45 +133,6 @@ class GroupView extends React.Component {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
onCreateRepoToggle = () => {
|
|
||||||
this.setState({ isCreateRepoDialogShow: !this.state.isCreateRepoDialogShow });
|
|
||||||
};
|
|
||||||
|
|
||||||
onCreateRepo = (repo, groupOwnerType) => {
|
|
||||||
let groupId = this.props.groupID;
|
|
||||||
if (groupOwnerType && groupOwnerType === 'department') {
|
|
||||||
seafileAPI.createGroupOwnedLibrary(groupId, repo).then(res => { // need modify endpoint api
|
|
||||||
let object = {
|
|
||||||
repo_id: res.data.id,
|
|
||||||
repo_name: res.data.name,
|
|
||||||
owner_name: res.data.group_name,
|
|
||||||
owner_email: res.data.owner,
|
|
||||||
permission: res.data.permission,
|
|
||||||
mtime: res.data.mtime,
|
|
||||||
size: res.data.size,
|
|
||||||
encrypted: res.data.encrypted,
|
|
||||||
};
|
|
||||||
let repo = new Repo(object);
|
|
||||||
let repoList = this.addRepoItem(repo);
|
|
||||||
this.setState({ repoList: repoList });
|
|
||||||
}).catch(error => {
|
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
|
||||||
toaster.danger(errMessage);
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
seafileAPI.createGroupRepo(groupId, repo).then(res => {
|
|
||||||
let repo = new Repo(res.data);
|
|
||||||
let repoList = this.addRepoItem(repo);
|
|
||||||
this.setState({ repoList: repoList });
|
|
||||||
}).catch(error => {
|
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
|
||||||
toaster.danger(errMessage);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.onCreateRepoToggle();
|
|
||||||
};
|
|
||||||
|
|
||||||
onItemDelete = (repo) => {
|
onItemDelete = (repo) => {
|
||||||
let repoList = this.state.repoList.filter(item => {
|
let repoList = this.state.repoList.filter(item => {
|
||||||
return item.repo_id !== repo.repo_id;
|
return item.repo_id !== repo.repo_id;
|
||||||
@ -217,12 +149,6 @@ class GroupView extends React.Component {
|
|||||||
this.loadGroup(this.props.groupID);
|
this.loadGroup(this.props.groupID);
|
||||||
};
|
};
|
||||||
|
|
||||||
addRepoItem = (repo) => {
|
|
||||||
let newRepoList = this.state.repoList.map(item => {return item;});
|
|
||||||
newRepoList.unshift(repo);
|
|
||||||
return newRepoList;
|
|
||||||
};
|
|
||||||
|
|
||||||
onItemUnshare = (repo) => {
|
onItemUnshare = (repo) => {
|
||||||
let group = this.state.currentGroup;
|
let group = this.state.currentGroup;
|
||||||
seafileAPI.unshareRepoToGroup(repo.repo_id, group.id).then(() => {
|
seafileAPI.unshareRepoToGroup(repo.repo_id, group.id).then(() => {
|
||||||
@ -262,66 +188,6 @@ class GroupView extends React.Component {
|
|||||||
this.setState({ repoList: repoList });
|
this.setState({ repoList: repoList });
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleDismissGroupDialog = () => {
|
|
||||||
this.setState({
|
|
||||||
showDismissGroupDialog: !this.state.showDismissGroupDialog,
|
|
||||||
showGroupDropdown: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleRenameGroupDialog = () => {
|
|
||||||
this.setState({
|
|
||||||
showRenameGroupDialog: !this.state.showRenameGroupDialog,
|
|
||||||
showGroupDropdown: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleTransferGroupDialog = () => {
|
|
||||||
this.setState({
|
|
||||||
showTransferGroupDialog: !this.state.showTransferGroupDialog,
|
|
||||||
showGroupDropdown: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleImportMembersDialog = () => {
|
|
||||||
this.setState({
|
|
||||||
showImportMembersDialog: !this.state.showImportMembersDialog
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleInviteMembersDialog = () => {
|
|
||||||
this.setState({
|
|
||||||
showInviteMembersDialog: !this.state.showInviteMembersDialog,
|
|
||||||
showGroupDropdown: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
importMembersInBatch = (file) => {
|
|
||||||
toaster.notify(gettext('It may take some time, please wait.'));
|
|
||||||
seafileAPI.importGroupMembersViaFile(this.state.currentGroup.id, file).then((res) => {
|
|
||||||
res.data.failed.forEach(item => {
|
|
||||||
toaster.danger(`${item.email}: ${item.error_msg}`);
|
|
||||||
});
|
|
||||||
}).catch((error) => {
|
|
||||||
let errMsg = Utils.getErrorMsg(error);
|
|
||||||
toaster.danger(errMsg);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleManageMembersDialog = () => {
|
|
||||||
this.setState({
|
|
||||||
showManageMembersDialog: !this.state.showManageMembersDialog,
|
|
||||||
showGroupDropdown: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleLeaveGroupDialog = () => {
|
|
||||||
this.setState({
|
|
||||||
isLeaveGroupDialogOpen: !this.state.isLeaveGroupDialogOpen,
|
|
||||||
showGroupDropdown: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
sortItems = (sortBy, sortOrder) => {
|
sortItems = (sortBy, sortOrder) => {
|
||||||
cookie.save('seafile-repo-dir-sort-by', sortBy);
|
cookie.save('seafile-repo-dir-sort-by', sortBy);
|
||||||
cookie.save('seafile-repo-dir-sort-order', sortOrder);
|
cookie.save('seafile-repo-dir-sort-order', sortOrder);
|
||||||
@ -332,18 +198,6 @@ class GroupView extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
translateRole = (role) => {
|
|
||||||
if (role === 'Admin') {
|
|
||||||
return gettext('Admin');
|
|
||||||
}
|
|
||||||
else if (role === 'Member') {
|
|
||||||
return gettext('Member');
|
|
||||||
}
|
|
||||||
else if (role === 'Owner') {
|
|
||||||
return gettext('Owner');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleSortOptionsDialog = () => {
|
toggleSortOptionsDialog = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
isSortOptionsDialogOpen: !this.state.isSortOptionsDialogOpen
|
isSortOptionsDialogOpen: !this.state.isSortOptionsDialogOpen
|
||||||
@ -366,47 +220,6 @@ class GroupView extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleMembersDialog = () => {
|
|
||||||
this.setState({
|
|
||||||
isMembersDialogOpen: !this.state.isMembersDialogOpen
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getOpList = () => {
|
|
||||||
const { currentGroup, isDepartmentGroup, isStaff, isOwner } = this.state;
|
|
||||||
const opList = [];
|
|
||||||
if ((!isDepartmentGroup && canAddRepo) ||
|
|
||||||
(isDepartmentGroup && isStaff)) {
|
|
||||||
this.newLibraryEnalbed = true;
|
|
||||||
opList.push({ 'text': gettext('New Library'), 'onClick': this.onCreateRepoToggle }, 'Divider');
|
|
||||||
}
|
|
||||||
opList.push({ 'text': gettext('Members'), 'onClick': this.toggleMembersDialog });
|
|
||||||
if (currentGroup) {
|
|
||||||
if (isStaff || isOwner) {
|
|
||||||
opList.push({ 'text': gettext('Import members'), 'onClick': this.toggleImportMembersDialog });
|
|
||||||
opList.push({ 'text': gettext('Manage members'), 'onClick': this.toggleManageMembersDialog });
|
|
||||||
opList.push('Divider');
|
|
||||||
opList.push({ 'text': gettext('Rename'), 'onClick': this.toggleRenameGroupDialog });
|
|
||||||
if (isOwner) {
|
|
||||||
opList.push({ 'text': gettext('Transfer'), 'onClick': this.toggleTransferGroupDialog });
|
|
||||||
}
|
|
||||||
if (isOwner) {
|
|
||||||
opList.push({ 'text': gettext('Delete group'), 'onClick': this.toggleDismissGroupDialog });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isOwner && !isDepartmentGroup) {
|
|
||||||
opList.push({ 'text': gettext('Leave group'), 'onClick': this.toggleLeaveGroupDialog });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOwner && this.state.currentGroup.owner !== 'system admin' && !isMultiTenancy) {
|
|
||||||
opList.push({ 'text': gettext('Invite members'), 'onClick': this.toggleInviteMembersDialog });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return opList;
|
|
||||||
};
|
|
||||||
|
|
||||||
switchViewMode = (newMode) => {
|
switchViewMode = (newMode) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
currentViewMode: newMode
|
currentViewMode: newMode
|
||||||
@ -422,16 +235,38 @@ class GroupView extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleDepartmentDetailDialog = () => {
|
addNewRepo = (newRepo) => {
|
||||||
|
let { repoList } = this.state;
|
||||||
|
repoList.unshift(newRepo);
|
||||||
|
this.setState({ repoList: repoList });
|
||||||
|
};
|
||||||
|
|
||||||
|
onGroupNameChanged = (newName) => {
|
||||||
|
const { currentGroup } = this.state;
|
||||||
|
currentGroup.name = newName;
|
||||||
this.setState({
|
this.setState({
|
||||||
isShowDepartmentDetailDialog: !this.state.isShowDepartmentDetailDialog
|
currentGroup: currentGroup
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onGroupTransfered = (group) => {
|
||||||
|
this.setState({
|
||||||
|
currentGroup: group
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onGroupDeleted = () => {
|
||||||
|
navigate(siteRoot);
|
||||||
|
};
|
||||||
|
|
||||||
|
onLeavingGroup = () => {
|
||||||
|
navigate(siteRoot);
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
isLoading, repoList, errMessage, emptyTip,
|
isLoading, repoList, errMessage, emptyTip,
|
||||||
currentGroup, isDepartmentGroup, isMembersDialogOpen,
|
currentGroup, isDepartmentGroup,
|
||||||
currentViewMode, sortBy, sortOrder
|
currentViewMode, sortBy, sortOrder
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
@ -440,7 +275,6 @@ class GroupView extends React.Component {
|
|||||||
useRate = currentGroup.group_quota_usage / currentGroup.group_quota * 100 + '%';
|
useRate = currentGroup.group_quota_usage / currentGroup.group_quota * 100 + '%';
|
||||||
}
|
}
|
||||||
|
|
||||||
const opList = this.getOpList();
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="main-panel-center flex-row">
|
<div className="main-panel-center flex-row">
|
||||||
@ -453,9 +287,13 @@ class GroupView extends React.Component {
|
|||||||
<span className="sf3-font-department sf3-font nav-icon" title={gettext('This is a special group representing a department.')}></span>
|
<span className="sf3-font-department sf3-font nav-icon" title={gettext('This is a special group representing a department.')}></span>
|
||||||
}
|
}
|
||||||
<span>{currentGroup.name}</span>
|
<span>{currentGroup.name}</span>
|
||||||
<SingleDropdownToolbar
|
<GroupOperationMenu
|
||||||
withPlusIcon={this.newLibraryEnalbed}
|
group={currentGroup}
|
||||||
opList={opList}
|
addNewRepo={this.addNewRepo}
|
||||||
|
onGroupNameChanged={this.onGroupNameChanged}
|
||||||
|
onGroupTransfered={this.onGroupTransfered}
|
||||||
|
onGroupDeleted={this.onGroupDeleted}
|
||||||
|
onLeavingGroup={this.onLeavingGroup}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="path-tool d-flex align-items-center">
|
<div className="path-tool d-flex align-items-center">
|
||||||
@ -523,91 +361,6 @@ class GroupView extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{this.state.isCreateRepoDialogShow && !this.state.isDepartmentGroup && (
|
|
||||||
<ModalPortal>
|
|
||||||
<CreateRepoDialog
|
|
||||||
libraryType={this.state.libraryType}
|
|
||||||
onCreateToggle={this.onCreateRepoToggle}
|
|
||||||
onCreateRepo={this.onCreateRepo}
|
|
||||||
/>
|
|
||||||
</ModalPortal>
|
|
||||||
)}
|
|
||||||
{this.state.isCreateRepoDialogShow && this.state.isDepartmentGroup &&
|
|
||||||
<CreateRepoDialog
|
|
||||||
onCreateToggle={this.onCreateRepoToggle}
|
|
||||||
onCreateRepo={this.onCreateRepo}
|
|
||||||
libraryType='department'
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{isMembersDialogOpen &&
|
|
||||||
<GroupMembersDialog
|
|
||||||
groupID={this.props.groupID}
|
|
||||||
toggleDialog={this.toggleMembersDialog}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{this.state.showRenameGroupDialog &&
|
|
||||||
<RenameGroupDialog
|
|
||||||
showRenameGroupDialog={this.state.showRenameGroupDialog}
|
|
||||||
toggleRenameGroupDialog={this.toggleRenameGroupDialog}
|
|
||||||
loadGroup={this.loadGroup}
|
|
||||||
groupID={this.props.groupID}
|
|
||||||
onGroupChanged={this.props.onGroupChanged}
|
|
||||||
currentGroupName={currentGroup.name}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{this.state.showDismissGroupDialog &&
|
|
||||||
<DismissGroupDialog
|
|
||||||
showDismissGroupDialog={this.state.showDismissGroupDialog}
|
|
||||||
toggleDismissGroupDialog={this.toggleDismissGroupDialog}
|
|
||||||
loadGroup={this.loadGroup}
|
|
||||||
groupID={this.props.groupID}
|
|
||||||
onGroupChanged={this.props.onGroupChanged}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{this.state.showTransferGroupDialog &&
|
|
||||||
<TransferGroupDialog
|
|
||||||
toggleTransferGroupDialog={this.toggleTransferGroupDialog}
|
|
||||||
groupID={this.props.groupID}
|
|
||||||
onGroupChanged={this.props.onGroupChanged}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{ this.state.showImportMembersDialog &&
|
|
||||||
<ImportMembersDialog
|
|
||||||
toggleImportMembersDialog={this.toggleImportMembersDialog}
|
|
||||||
importMembersInBatch={this.importMembersInBatch}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{this.state.showManageMembersDialog &&
|
|
||||||
<ManageMembersDialog
|
|
||||||
toggleManageMembersDialog={this.toggleManageMembersDialog}
|
|
||||||
groupID={this.props.groupID}
|
|
||||||
onGroupChanged={this.props.onGroupChanged}
|
|
||||||
isOwner={this.state.isOwner}
|
|
||||||
toggleDepartmentDetailDialog={this.toggleDepartmentDetailDialog}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{this.state.isShowDepartmentDetailDialog &&
|
|
||||||
<DepartmentDetailDialog
|
|
||||||
usedFor='add_group_member'
|
|
||||||
toggleDepartmentDetailDialog={this.toggleDepartmentDetailDialog}
|
|
||||||
toggleManageMembersDialog={this.toggleManageMembersDialog}
|
|
||||||
groupID={this.props.groupID}
|
|
||||||
isOwner={this.state.isOwner}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{this.state.isLeaveGroupDialogOpen &&
|
|
||||||
<LeaveGroupDialog
|
|
||||||
toggleLeaveGroupDialog={this.toggleLeaveGroupDialog}
|
|
||||||
groupID={this.props.groupID}
|
|
||||||
onGroupChanged={this.props.onGroupChanged}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{this.state.showInviteMembersDialog &&
|
|
||||||
<GroupInviteMembersDialog
|
|
||||||
groupID={this.props.groupID}
|
|
||||||
toggleInviteMembersDialog={this.toggleInviteMembersDialog}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ class Libraries extends Component {
|
|||||||
|
|
||||||
const eventBus = EventBus.getInstance();
|
const eventBus = EventBus.getInstance();
|
||||||
this.unsubscribeAddNewGroup = eventBus.subscribe(EVENT_BUS_TYPE.ADD_NEW_GROUP, this.addNewGroup);
|
this.unsubscribeAddNewGroup = eventBus.subscribe(EVENT_BUS_TYPE.ADD_NEW_GROUP, this.addNewGroup);
|
||||||
this.unsubscribeAddSharedRepoIntoGroup = eventBus.subscribe(EVENT_BUS_TYPE.ADD_SHARED_REPO_INTO_GROUP, this.insertRepoIntoGroup);
|
this.unsubscribeAddSharedRepoIntoGroup = eventBus.subscribe(EVENT_BUS_TYPE.ADD_SHARED_REPO_INTO_GROUP, this.addRepoToGroup);
|
||||||
this.unsubscribeUnsharedRepoToGroup = eventBus.subscribe(EVENT_BUS_TYPE.UN_SHARE_REPO_TO_GROUP, this.unshareRepoToGroup);
|
this.unsubscribeUnsharedRepoToGroup = eventBus.subscribe(EVENT_BUS_TYPE.UN_SHARE_REPO_TO_GROUP, this.unshareRepoToGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,7 +282,7 @@ class Libraries extends Component {
|
|||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
insertRepoIntoGroup = ({ repo, group_id }) => {
|
addRepoToGroup = ({ repo, group_id }) => {
|
||||||
if (!repo) {
|
if (!repo) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -299,11 +299,37 @@ class Libraries extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
targetGroup.repos.unshift(repo);
|
targetGroup.repos.unshift(repo);
|
||||||
targetGroup.repos = Utils.sortRepos(targetGroup.repos, this.state.sortBy, this.state.sortOrder);
|
|
||||||
this.groupsReposManager.add(repo.repo_id, group_id);
|
this.groupsReposManager.add(repo.repo_id, group_id);
|
||||||
this.setState({ groupList: newGroupList });
|
this.setState({ groupList: newGroupList });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onGroupNameChanged = (newName, groupID) => {
|
||||||
|
const { groupList } = this.state;
|
||||||
|
let newGroupList = [...groupList];
|
||||||
|
let targetGroup = newGroupList.find((group) => group.id === groupID);
|
||||||
|
targetGroup.name = newName;
|
||||||
|
this.setState({ groupList: newGroupList });
|
||||||
|
};
|
||||||
|
|
||||||
|
onGroupTransfered = (group) => {
|
||||||
|
const { groupList } = this.state;
|
||||||
|
let newGroupList = [...groupList];
|
||||||
|
let targetGroup = newGroupList.find((item) => item.id === group.id);
|
||||||
|
targetGroup.owner = group.owner;
|
||||||
|
targetGroup.admins = group.admins;
|
||||||
|
this.setState({ groupList: newGroupList });
|
||||||
|
};
|
||||||
|
|
||||||
|
onGroupDeleted = (groupID) => {
|
||||||
|
const { groupList } = this.state;
|
||||||
|
this.setState({ groupList: groupList.filter(item => item.id != groupID) });
|
||||||
|
};
|
||||||
|
|
||||||
|
onLeavingGroup = (groupID) => {
|
||||||
|
const { groupList } = this.state;
|
||||||
|
this.setState({ groupList: groupList.filter(item => item.id != groupID) });
|
||||||
|
};
|
||||||
|
|
||||||
unshareRepoToGroup = ({ repo_id, group_id }) => {
|
unshareRepoToGroup = ({ repo_id, group_id }) => {
|
||||||
const { groupList } = this.state;
|
const { groupList } = this.state;
|
||||||
let newGroupList = [...groupList];
|
let newGroupList = [...groupList];
|
||||||
@ -498,7 +524,11 @@ class Libraries extends Component {
|
|||||||
onMonitorRepo={this.onMonitorRepo}
|
onMonitorRepo={this.onMonitorRepo}
|
||||||
renameRelatedGroupsRepos={this.renameRelatedGroupsRepos}
|
renameRelatedGroupsRepos={this.renameRelatedGroupsRepos}
|
||||||
deleteRelatedGroupsRepos={this.deleteRelatedGroupsRepos}
|
deleteRelatedGroupsRepos={this.deleteRelatedGroupsRepos}
|
||||||
insertRepoIntoGroup={this.insertRepoIntoGroup}
|
addRepoToGroup={this.addRepoToGroup}
|
||||||
|
onGroupNameChanged={this.onGroupNameChanged}
|
||||||
|
onGroupTransfered={this.onGroupTransfered}
|
||||||
|
onGroupDeleted={this.onGroupDeleted}
|
||||||
|
onLeavingGroup={this.onLeavingGroup}
|
||||||
unshareRepoToGroup={this.unshareRepoToGroup}
|
unshareRepoToGroup={this.unshareRepoToGroup}
|
||||||
onTransferRepo={this.onGroupTransferRepo}
|
onTransferRepo={this.onGroupTransferRepo}
|
||||||
currentViewMode={currentViewMode}
|
currentViewMode={currentViewMode}
|
||||||
|
@ -6,6 +6,7 @@ class DepartmentNode {
|
|||||||
this.children = props.children || [];
|
this.children = props.children || [];
|
||||||
this.parentNode = props.parentNode || null;
|
this.parentNode = props.parentNode || null;
|
||||||
this.orgId = props.orgId || '';
|
this.orgId = props.orgId || '';
|
||||||
|
this.quota = props.quota || -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
findNodeById(nodeId) {
|
findNodeById(nodeId) {
|
||||||
|
@ -132,6 +132,7 @@ class Department extends React.Component {
|
|||||||
<DepartmentNodeMenu
|
<DepartmentNodeMenu
|
||||||
node={currentDepartment}
|
node={currentDepartment}
|
||||||
toggleAddDepartment={this.props.toggleAddDepartment}
|
toggleAddDepartment={this.props.toggleAddDepartment}
|
||||||
|
toggleSetQuotaDialog={this.props.toggleSetQuotaDialog}
|
||||||
toggleAddLibrary={this.props.toggleAddLibrary}
|
toggleAddLibrary={this.props.toggleAddLibrary}
|
||||||
toggleAddMembers={this.props.toggleAddMembers}
|
toggleAddMembers={this.props.toggleAddMembers}
|
||||||
toggleRename={this.props.toggleRename}
|
toggleRename={this.props.toggleRename}
|
||||||
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|||||||
import { DropdownItem, DropdownMenu } from 'reactstrap';
|
import { DropdownItem, DropdownMenu } from 'reactstrap';
|
||||||
import { gettext } from '../../../utils/constants';
|
import { gettext } from '../../../utils/constants';
|
||||||
|
|
||||||
function DepartmentNodeMenu({ node, toggleDelete, toggleRename, toggleAddMembers, toggleAddDepartment, toggleAddLibrary }) {
|
function DepartmentNodeMenu({ node, toggleDelete, toggleRename, toggleAddMembers, toggleAddDepartment, toggleAddLibrary, toggleSetQuotaDialog }) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
modifiers={[{ name: 'preventOverflow', options: { boundary: document.body } }]}
|
modifiers={[{ name: 'preventOverflow', options: { boundary: document.body } }]}
|
||||||
@ -24,6 +24,9 @@ function DepartmentNodeMenu({ node, toggleDelete, toggleRename, toggleAddMembers
|
|||||||
<DropdownItem key={`${node.id}-delete`} onClick={() => toggleDelete(node)}>
|
<DropdownItem key={`${node.id}-delete`} onClick={() => toggleDelete(node)}>
|
||||||
{gettext('Delete')}
|
{gettext('Delete')}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
|
<DropdownItem key={`${node.id}-set-quota`} onClick={() => toggleSetQuotaDialog(node)}>
|
||||||
|
{gettext('Set quota')}
|
||||||
|
</DropdownItem>
|
||||||
<DropdownItem key={`${node.id}-id`} disabled={true}>
|
<DropdownItem key={`${node.id}-id`} disabled={true}>
|
||||||
{`${gettext('Department ID')} : ${node.id}`}
|
{`${gettext('Department ID')} : ${node.id}`}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
@ -38,6 +41,7 @@ DepartmentNodeMenu.propTypes = {
|
|||||||
toggleAddMembers: PropTypes.func.isRequired,
|
toggleAddMembers: PropTypes.func.isRequired,
|
||||||
toggleAddDepartment: PropTypes.func.isRequired,
|
toggleAddDepartment: PropTypes.func.isRequired,
|
||||||
toggleAddLibrary: PropTypes.func.isRequired,
|
toggleAddLibrary: PropTypes.func.isRequired,
|
||||||
|
toggleSetQuotaDialog: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DepartmentNodeMenu;
|
export default DepartmentNodeMenu;
|
||||||
|
@ -9,6 +9,7 @@ const DepartmentsTreePanelPropTypes = {
|
|||||||
onChangeDepartment: PropTypes.func,
|
onChangeDepartment: PropTypes.func,
|
||||||
listSubDepartments: PropTypes.func,
|
listSubDepartments: PropTypes.func,
|
||||||
toggleAddDepartment: PropTypes.func,
|
toggleAddDepartment: PropTypes.func,
|
||||||
|
toggleSetQuotaDialog: PropTypes.func,
|
||||||
toggleAddLibrary: PropTypes.func,
|
toggleAddLibrary: PropTypes.func,
|
||||||
toggleAddMembers: PropTypes.func,
|
toggleAddMembers: PropTypes.func,
|
||||||
toggleRename: PropTypes.func,
|
toggleRename: PropTypes.func,
|
||||||
@ -29,6 +30,7 @@ class DepartmentsTreePanel extends Component {
|
|||||||
onChangeDepartment={this.props.onChangeDepartment}
|
onChangeDepartment={this.props.onChangeDepartment}
|
||||||
listSubDepartments={this.props.listSubDepartments}
|
listSubDepartments={this.props.listSubDepartments}
|
||||||
toggleAddDepartment={this.props.toggleAddDepartment}
|
toggleAddDepartment={this.props.toggleAddDepartment}
|
||||||
|
toggleSetQuotaDialog={this.props.toggleSetQuotaDialog}
|
||||||
toggleAddLibrary={this.props.toggleAddLibrary}
|
toggleAddLibrary={this.props.toggleAddLibrary}
|
||||||
toggleAddMembers={this.props.toggleAddMembers}
|
toggleAddMembers={this.props.toggleAddMembers}
|
||||||
toggleRename={this.props.toggleRename}
|
toggleRename={this.props.toggleRename}
|
||||||
|
@ -4,6 +4,7 @@ import { Utils } from '../../../utils/utils';
|
|||||||
import { gettext, orgID } from '../../../utils/constants';
|
import { gettext, orgID } from '../../../utils/constants';
|
||||||
import { orgAdminAPI } from '../../../utils/org-admin-api';
|
import { orgAdminAPI } from '../../../utils/org-admin-api';
|
||||||
import toaster from '../../../components/toast';
|
import toaster from '../../../components/toast';
|
||||||
|
import SetGroupQuotaDialog from '../../../components/dialog/org-set-group-quota-dialog';
|
||||||
import AddDepartmentDialog from '../../../components/dialog/sysadmin-dialog/add-department-v2-dialog';
|
import AddDepartmentDialog from '../../../components/dialog/sysadmin-dialog/add-department-v2-dialog';
|
||||||
import AddDepartMemberDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-add-depart-member-v2-dialog';
|
import AddDepartMemberDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-add-depart-member-v2-dialog';
|
||||||
import RenameDepartmentDialog from '../../../components/dialog/sysadmin-dialog/rename-department-v2-dialog';
|
import RenameDepartmentDialog from '../../../components/dialog/sysadmin-dialog/rename-department-v2-dialog';
|
||||||
@ -30,6 +31,7 @@ class Departments extends React.Component {
|
|||||||
isRenameDepartmentDialogShow: false,
|
isRenameDepartmentDialogShow: false,
|
||||||
isDeleteDepartmentDialogShow: false,
|
isDeleteDepartmentDialogShow: false,
|
||||||
isShowAddRepoDialog: false,
|
isShowAddRepoDialog: false,
|
||||||
|
isSetQuotaDialogShow: false,
|
||||||
membersList: [],
|
membersList: [],
|
||||||
isTopDepartmentLoading: false,
|
isTopDepartmentLoading: false,
|
||||||
isMembersListLoading: false,
|
isMembersListLoading: false,
|
||||||
@ -48,6 +50,7 @@ class Departments extends React.Component {
|
|||||||
id: item.id,
|
id: item.id,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
orgId: item.org_id,
|
orgId: item.org_id,
|
||||||
|
quota: item.quota,
|
||||||
});
|
});
|
||||||
return node;
|
return node;
|
||||||
});
|
});
|
||||||
@ -102,6 +105,7 @@ class Departments extends React.Component {
|
|||||||
parentGroupId: department.parent_group_id,
|
parentGroupId: department.parent_group_id,
|
||||||
orgId: department.org_id,
|
orgId: department.org_id,
|
||||||
parentNode: node,
|
parentNode: node,
|
||||||
|
quota: department.quota,
|
||||||
}));
|
}));
|
||||||
node.setChildren(childrenNodes);
|
node.setChildren(childrenNodes);
|
||||||
cb && cb(childrenNodes);
|
cb && cb(childrenNodes);
|
||||||
@ -285,6 +289,28 @@ class Departments extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
toggleSetQuotaDialog = (node) => {
|
||||||
|
this.setState({ operateNode: node, isSetQuotaDialogShow: !this.state.isSetQuotaDialogShow });
|
||||||
|
};
|
||||||
|
|
||||||
|
onSetQuota = (newNode) => {
|
||||||
|
const rootNodes = this.state.rootNodes.slice(0);
|
||||||
|
this._setQuota(rootNodes[0], newNode);
|
||||||
|
this.setState({
|
||||||
|
rootNodes: rootNodes
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_setQuota = (node, newNode) => {
|
||||||
|
if (node.id === newNode.id) {
|
||||||
|
node.quota = newNode.quota;
|
||||||
|
} else {
|
||||||
|
node.children.forEach(child => {
|
||||||
|
this._setQuota(child, newNode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { rootNodes, operateNode, checkedDepartmentId, isAddDepartmentDialogShow, isAddMembersDialogShow,
|
const { rootNodes, operateNode, checkedDepartmentId, isAddDepartmentDialogShow, isAddMembersDialogShow,
|
||||||
@ -308,6 +334,7 @@ class Departments extends React.Component {
|
|||||||
onChangeDepartment={this.onChangeDepartment}
|
onChangeDepartment={this.onChangeDepartment}
|
||||||
listSubDepartments={this.listSubDepartments}
|
listSubDepartments={this.listSubDepartments}
|
||||||
toggleAddDepartment={this.toggleAddDepartment}
|
toggleAddDepartment={this.toggleAddDepartment}
|
||||||
|
toggleSetQuotaDialog={this.toggleSetQuotaDialog}
|
||||||
toggleAddLibrary={this.toggleAddLibrary}
|
toggleAddLibrary={this.toggleAddLibrary}
|
||||||
toggleAddMembers={this.toggleAddMembers}
|
toggleAddMembers={this.toggleAddMembers}
|
||||||
toggleRename={this.toggleRename}
|
toggleRename={this.toggleRename}
|
||||||
@ -328,6 +355,7 @@ class Departments extends React.Component {
|
|||||||
deleteGroup={this.deleteGroup}
|
deleteGroup={this.deleteGroup}
|
||||||
createGroup={this.createGroup}
|
createGroup={this.createGroup}
|
||||||
toggleAddDepartment={this.toggleAddDepartment}
|
toggleAddDepartment={this.toggleAddDepartment}
|
||||||
|
toggleSetQuotaDialog={this.toggleSetQuotaDialog}
|
||||||
toggleAddLibrary={this.toggleAddLibrary}
|
toggleAddLibrary={this.toggleAddLibrary}
|
||||||
toggleAddMembers={this.toggleAddMembers}
|
toggleAddMembers={this.toggleAddMembers}
|
||||||
toggleRename={this.toggleRename}
|
toggleRename={this.toggleRename}
|
||||||
@ -384,6 +412,13 @@ class Departments extends React.Component {
|
|||||||
groupID={String(operateNode.id)}
|
groupID={String(operateNode.id)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{this.state.isSetQuotaDialogShow &&
|
||||||
|
<SetGroupQuotaDialog
|
||||||
|
group={operateNode}
|
||||||
|
onSetQuota={this.onSetQuota}
|
||||||
|
toggle={this.toggleSetQuotaDialog}
|
||||||
|
/>
|
||||||
|
}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ const departmentsV2TreeNodePropTypes = {
|
|||||||
listSubDepartments: PropTypes.func,
|
listSubDepartments: PropTypes.func,
|
||||||
onChangeDepartment: PropTypes.func,
|
onChangeDepartment: PropTypes.func,
|
||||||
toggleAddDepartment: PropTypes.func,
|
toggleAddDepartment: PropTypes.func,
|
||||||
|
toggleSetQuotaDialog: PropTypes.func,
|
||||||
toggleAddLibrary: PropTypes.func,
|
toggleAddLibrary: PropTypes.func,
|
||||||
toggleAddMembers: PropTypes.func,
|
toggleAddMembers: PropTypes.func,
|
||||||
toggleRename: PropTypes.func,
|
toggleRename: PropTypes.func,
|
||||||
@ -85,6 +86,7 @@ class DepartmentsV2TreeNode extends Component {
|
|||||||
toggleRename={this.props.toggleRename}
|
toggleRename={this.props.toggleRename}
|
||||||
toggleDelete={this.props.toggleDelete}
|
toggleDelete={this.props.toggleDelete}
|
||||||
toggleAddLibrary={this.props.toggleAddLibrary}
|
toggleAddLibrary={this.props.toggleAddLibrary}
|
||||||
|
toggleSetQuotaDialog={this.props.toggleSetQuotaDialog}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -151,6 +153,7 @@ class DepartmentsV2TreeNode extends Component {
|
|||||||
toggleAddDepartment={this.props.toggleAddDepartment}
|
toggleAddDepartment={this.props.toggleAddDepartment}
|
||||||
toggleAddLibrary={this.props.toggleAddLibrary}
|
toggleAddLibrary={this.props.toggleAddLibrary}
|
||||||
toggleAddMembers={this.props.toggleAddMembers}
|
toggleAddMembers={this.props.toggleAddMembers}
|
||||||
|
toggleSetQuotaDialog={this.props.toggleSetQuotaDialog}
|
||||||
toggleRename={this.props.toggleRename}
|
toggleRename={this.props.toggleRename}
|
||||||
toggleDelete={this.props.toggleDelete}
|
toggleDelete={this.props.toggleDelete}
|
||||||
/>
|
/>
|
||||||
|
@ -6,6 +6,7 @@ class DepartmentNode {
|
|||||||
this.children = props.children || [];
|
this.children = props.children || [];
|
||||||
this.parentNode = props.parentNode || null;
|
this.parentNode = props.parentNode || null;
|
||||||
this.orgId = props.orgId || '';
|
this.orgId = props.orgId || '';
|
||||||
|
this.quota = props.quota || -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
findNodeById(nodeId) {
|
findNodeById(nodeId) {
|
||||||
|
@ -155,6 +155,7 @@ class Department extends React.Component {
|
|||||||
<DepartmentNodeMenu
|
<DepartmentNodeMenu
|
||||||
node={currentDepartment}
|
node={currentDepartment}
|
||||||
toggleAddDepartment={this.props.toggleAddDepartment}
|
toggleAddDepartment={this.props.toggleAddDepartment}
|
||||||
|
toggleSetQuotaDialog={this.props.toggleSetQuotaDialog}
|
||||||
toggleAddLibrary={this.props.toggleAddLibrary}
|
toggleAddLibrary={this.props.toggleAddLibrary}
|
||||||
toggleAddMembers={this.props.toggleAddMembers}
|
toggleAddMembers={this.props.toggleAddMembers}
|
||||||
toggleRename={this.props.toggleRename}
|
toggleRename={this.props.toggleRename}
|
||||||
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|||||||
import { DropdownItem, DropdownMenu } from 'reactstrap';
|
import { DropdownItem, DropdownMenu } from 'reactstrap';
|
||||||
import { gettext } from '../../../utils/constants';
|
import { gettext } from '../../../utils/constants';
|
||||||
|
|
||||||
function DepartmentNodeMenu({ node, toggleDelete, toggleRename, toggleAddMembers, toggleAddDepartment, toggleAddLibrary }) {
|
function DepartmentNodeMenu({ node, toggleDelete, toggleRename, toggleAddMembers, toggleAddDepartment, toggleAddLibrary, toggleSetQuotaDialog }) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
modifiers={[{ name: 'preventOverflow', options: { boundary: document.body } }]}
|
modifiers={[{ name: 'preventOverflow', options: { boundary: document.body } }]}
|
||||||
@ -24,6 +24,9 @@ function DepartmentNodeMenu({ node, toggleDelete, toggleRename, toggleAddMembers
|
|||||||
<DropdownItem key={`${node.id}-delete`} onClick={() => toggleDelete(node)}>
|
<DropdownItem key={`${node.id}-delete`} onClick={() => toggleDelete(node)}>
|
||||||
{gettext('Delete')}
|
{gettext('Delete')}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
|
<DropdownItem key={`${node.id}-set-quota`} onClick={() => toggleSetQuotaDialog(node)}>
|
||||||
|
{gettext('Set quota')}
|
||||||
|
</DropdownItem>
|
||||||
<DropdownItem key={`${node.id}-id`} disabled={true}>
|
<DropdownItem key={`${node.id}-id`} disabled={true}>
|
||||||
{`${gettext('Department ID')} : ${node.id}`}
|
{`${gettext('Department ID')} : ${node.id}`}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
@ -38,6 +41,7 @@ DepartmentNodeMenu.propTypes = {
|
|||||||
toggleAddMembers: PropTypes.func.isRequired,
|
toggleAddMembers: PropTypes.func.isRequired,
|
||||||
toggleAddDepartment: PropTypes.func.isRequired,
|
toggleAddDepartment: PropTypes.func.isRequired,
|
||||||
toggleAddLibrary: PropTypes.func.isRequired,
|
toggleAddLibrary: PropTypes.func.isRequired,
|
||||||
|
toggleSetQuotaDialog: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DepartmentNodeMenu;
|
export default DepartmentNodeMenu;
|
||||||
|
@ -9,6 +9,7 @@ const DepartmentsTreePanelPropTypes = {
|
|||||||
onChangeDepartment: PropTypes.func,
|
onChangeDepartment: PropTypes.func,
|
||||||
listSubDepartments: PropTypes.func,
|
listSubDepartments: PropTypes.func,
|
||||||
toggleAddDepartment: PropTypes.func,
|
toggleAddDepartment: PropTypes.func,
|
||||||
|
toggleSetQuotaDialog: PropTypes.func,
|
||||||
toggleAddLibrary: PropTypes.func,
|
toggleAddLibrary: PropTypes.func,
|
||||||
toggleAddMembers: PropTypes.func,
|
toggleAddMembers: PropTypes.func,
|
||||||
toggleRename: PropTypes.func,
|
toggleRename: PropTypes.func,
|
||||||
@ -29,6 +30,7 @@ class DepartmentsTreePanel extends Component {
|
|||||||
onChangeDepartment={this.props.onChangeDepartment}
|
onChangeDepartment={this.props.onChangeDepartment}
|
||||||
listSubDepartments={this.props.listSubDepartments}
|
listSubDepartments={this.props.listSubDepartments}
|
||||||
toggleAddDepartment={this.props.toggleAddDepartment}
|
toggleAddDepartment={this.props.toggleAddDepartment}
|
||||||
|
toggleSetQuotaDialog={this.props.toggleSetQuotaDialog}
|
||||||
toggleAddLibrary={this.props.toggleAddLibrary}
|
toggleAddLibrary={this.props.toggleAddLibrary}
|
||||||
toggleAddMembers={this.props.toggleAddMembers}
|
toggleAddMembers={this.props.toggleAddMembers}
|
||||||
toggleRename={this.props.toggleRename}
|
toggleRename={this.props.toggleRename}
|
||||||
|
@ -5,6 +5,7 @@ import { Utils } from '../../../utils/utils';
|
|||||||
import { systemAdminAPI } from '../../../utils/system-admin-api';
|
import { systemAdminAPI } from '../../../utils/system-admin-api';
|
||||||
import Loading from '../../../components/loading';
|
import Loading from '../../../components/loading';
|
||||||
import toaster from '../../../components/toast';
|
import toaster from '../../../components/toast';
|
||||||
|
import SetGroupQuotaDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-set-group-quota-dialog';
|
||||||
import AddDepartmentV2Dialog from '../../../components/dialog/sysadmin-dialog/add-department-v2-dialog';
|
import AddDepartmentV2Dialog from '../../../components/dialog/sysadmin-dialog/add-department-v2-dialog';
|
||||||
import AddDepartMemberV2Dialog from '../../../components/dialog/sysadmin-dialog/sysadmin-add-depart-member-v2-dialog';
|
import AddDepartMemberV2Dialog from '../../../components/dialog/sysadmin-dialog/sysadmin-add-depart-member-v2-dialog';
|
||||||
import RenameDepartmentV2Dialog from '../../../components/dialog/sysadmin-dialog/rename-department-v2-dialog';
|
import RenameDepartmentV2Dialog from '../../../components/dialog/sysadmin-dialog/rename-department-v2-dialog';
|
||||||
@ -25,6 +26,7 @@ class Departments extends React.Component {
|
|||||||
rootNodes: [],
|
rootNodes: [],
|
||||||
checkedDepartmentId: -1,
|
checkedDepartmentId: -1,
|
||||||
operateNode: null,
|
operateNode: null,
|
||||||
|
isSetQuotaDialogShow: false,
|
||||||
isAddDepartmentDialogShow: false,
|
isAddDepartmentDialogShow: false,
|
||||||
isAddMembersDialogShow: false,
|
isAddMembersDialogShow: false,
|
||||||
isRenameDepartmentDialogShow: false,
|
isRenameDepartmentDialogShow: false,
|
||||||
@ -51,6 +53,7 @@ class Departments extends React.Component {
|
|||||||
id: item.id,
|
id: item.id,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
orgId: item.org_id,
|
orgId: item.org_id,
|
||||||
|
quota: item.quota,
|
||||||
});
|
});
|
||||||
return node;
|
return node;
|
||||||
});
|
});
|
||||||
@ -135,6 +138,7 @@ class Departments extends React.Component {
|
|||||||
parentGroupId: department.parent_group_id,
|
parentGroupId: department.parent_group_id,
|
||||||
orgId: department.org_id,
|
orgId: department.org_id,
|
||||||
parentNode: node,
|
parentNode: node,
|
||||||
|
quota: department.quota,
|
||||||
}));
|
}));
|
||||||
node.setChildren(childrenNodes);
|
node.setChildren(childrenNodes);
|
||||||
cb && cb(childrenNodes);
|
cb && cb(childrenNodes);
|
||||||
@ -168,6 +172,10 @@ class Departments extends React.Component {
|
|||||||
this.setState({ operateNode: node, isAddDepartmentDialogShow: !this.state.isAddDepartmentDialogShow });
|
this.setState({ operateNode: node, isAddDepartmentDialogShow: !this.state.isAddDepartmentDialogShow });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
toggleSetQuotaDialog = (node) => {
|
||||||
|
this.setState({ operateNode: node, isSetQuotaDialogShow: !this.state.isSetQuotaDialogShow });
|
||||||
|
};
|
||||||
|
|
||||||
toggleAddMembers = (node) => {
|
toggleAddMembers = (node) => {
|
||||||
this.setState({ operateNode: node, isAddMembersDialogShow: !this.state.isAddMembersDialogShow });
|
this.setState({ operateNode: node, isAddMembersDialogShow: !this.state.isAddMembersDialogShow });
|
||||||
};
|
};
|
||||||
@ -318,6 +326,24 @@ class Departments extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onSetQuota = (newNode) => {
|
||||||
|
const rootNodes = this.state.rootNodes.slice(0);
|
||||||
|
this._setQuota(rootNodes[0], newNode);
|
||||||
|
this.setState({
|
||||||
|
rootNodes: rootNodes
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_setQuota = (node, newNode) => {
|
||||||
|
if (node.id === newNode.id) {
|
||||||
|
node.quota = newNode.quota;
|
||||||
|
} else {
|
||||||
|
node.children.forEach(child => {
|
||||||
|
this._setQuota(child, newNode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { rootNodes, operateNode, checkedDepartmentId, isAddDepartmentDialogShow, isAddMembersDialogShow,
|
const { rootNodes, operateNode, checkedDepartmentId, isAddDepartmentDialogShow, isAddMembersDialogShow,
|
||||||
@ -341,6 +367,7 @@ class Departments extends React.Component {
|
|||||||
onChangeDepartment={this.onChangeDepartment}
|
onChangeDepartment={this.onChangeDepartment}
|
||||||
listSubDepartments={this.listSubDepartments}
|
listSubDepartments={this.listSubDepartments}
|
||||||
toggleAddDepartment={this.toggleAddDepartment}
|
toggleAddDepartment={this.toggleAddDepartment}
|
||||||
|
toggleSetQuotaDialog={this.toggleSetQuotaDialog}
|
||||||
toggleAddLibrary={this.toggleAddLibrary}
|
toggleAddLibrary={this.toggleAddLibrary}
|
||||||
toggleAddMembers={this.toggleAddMembers}
|
toggleAddMembers={this.toggleAddMembers}
|
||||||
toggleRename={this.toggleRename}
|
toggleRename={this.toggleRename}
|
||||||
@ -361,6 +388,7 @@ class Departments extends React.Component {
|
|||||||
deleteGroup={this.deleteGroup}
|
deleteGroup={this.deleteGroup}
|
||||||
createGroup={this.createGroup}
|
createGroup={this.createGroup}
|
||||||
toggleAddDepartment={this.toggleAddDepartment}
|
toggleAddDepartment={this.toggleAddDepartment}
|
||||||
|
toggleSetQuotaDialog={this.toggleSetQuotaDialog}
|
||||||
toggleAddLibrary={this.toggleAddLibrary}
|
toggleAddLibrary={this.toggleAddLibrary}
|
||||||
toggleAddMembers={this.toggleAddMembers}
|
toggleAddMembers={this.toggleAddMembers}
|
||||||
toggleRename={this.toggleRename}
|
toggleRename={this.toggleRename}
|
||||||
@ -419,6 +447,13 @@ class Departments extends React.Component {
|
|||||||
groupID={String(operateNode.id)}
|
groupID={String(operateNode.id)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{this.state.isSetQuotaDialogShow &&
|
||||||
|
<SetGroupQuotaDialog
|
||||||
|
group={operateNode}
|
||||||
|
onSetQuota={this.onSetQuota}
|
||||||
|
toggle={this.toggleSetQuotaDialog}
|
||||||
|
/>
|
||||||
|
}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ const departmentsTreeNodePropTypes = {
|
|||||||
listSubDepartments: PropTypes.func,
|
listSubDepartments: PropTypes.func,
|
||||||
onChangeDepartment: PropTypes.func,
|
onChangeDepartment: PropTypes.func,
|
||||||
toggleAddDepartment: PropTypes.func,
|
toggleAddDepartment: PropTypes.func,
|
||||||
|
toggleSetQuotaDialog: PropTypes.func,
|
||||||
toggleAddLibrary: PropTypes.func,
|
toggleAddLibrary: PropTypes.func,
|
||||||
toggleAddMembers: PropTypes.func,
|
toggleAddMembers: PropTypes.func,
|
||||||
toggleRename: PropTypes.func,
|
toggleRename: PropTypes.func,
|
||||||
@ -81,6 +82,7 @@ class DepartmentsTreeNode extends Component {
|
|||||||
checkedDepartmentId={this.props.checkedDepartmentId}
|
checkedDepartmentId={this.props.checkedDepartmentId}
|
||||||
listSubDepartments={this.props.listSubDepartments}
|
listSubDepartments={this.props.listSubDepartments}
|
||||||
toggleAddDepartment={this.props.toggleAddDepartment}
|
toggleAddDepartment={this.props.toggleAddDepartment}
|
||||||
|
toggleSetQuotaDialog={this.props.toggleSetQuotaDialog}
|
||||||
toggleAddMembers={this.props.toggleAddMembers}
|
toggleAddMembers={this.props.toggleAddMembers}
|
||||||
toggleRename={this.props.toggleRename}
|
toggleRename={this.props.toggleRename}
|
||||||
toggleDelete={this.props.toggleDelete}
|
toggleDelete={this.props.toggleDelete}
|
||||||
@ -149,6 +151,7 @@ class DepartmentsTreeNode extends Component {
|
|||||||
<DepartmentNodeMenu
|
<DepartmentNodeMenu
|
||||||
node={node}
|
node={node}
|
||||||
toggleAddDepartment={this.props.toggleAddDepartment}
|
toggleAddDepartment={this.props.toggleAddDepartment}
|
||||||
|
toggleSetQuotaDialog={this.props.toggleSetQuotaDialog}
|
||||||
toggleAddLibrary={this.props.toggleAddLibrary}
|
toggleAddLibrary={this.props.toggleAddLibrary}
|
||||||
toggleAddMembers={this.props.toggleAddMembers}
|
toggleAddMembers={this.props.toggleAddMembers}
|
||||||
toggleRename={this.props.toggleRename}
|
toggleRename={this.props.toggleRename}
|
||||||
|
@ -15,7 +15,6 @@ import OpMenu from '../../../components/dialog/op-menu';
|
|||||||
import SysAdminUserSetQuotaDialog from '../../../components/dialog/sysadmin-dialog/set-quota';
|
import SysAdminUserSetQuotaDialog from '../../../components/dialog/sysadmin-dialog/set-quota';
|
||||||
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
|
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
|
||||||
import UserLink from '../user-link';
|
import UserLink from '../user-link';
|
||||||
import UsersFilterBar from './users-filter-bar';
|
|
||||||
|
|
||||||
const { availableRoles, availableAdminRoles, institutions } = window.sysadmin.pageOptions;
|
const { availableRoles, availableAdminRoles, institutions } = window.sysadmin.pageOptions;
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
@ -42,11 +41,11 @@ class Content extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
getPreviousPage = () => {
|
getPreviousPage = () => {
|
||||||
this.props.getListByPage(this.props.currentPage - 1, this.props.is_active, this.props.role);
|
this.props.getListByPage(this.props.currentPage - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
getNextPage = () => {
|
getNextPage = () => {
|
||||||
this.props.getListByPage(this.props.currentPage + 1, this.props.is_active, this.props.role);
|
this.props.getListByPage(this.props.currentPage + 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
sortByQuotaUsage = (e) => {
|
sortByQuotaUsage = (e) => {
|
||||||
@ -164,14 +163,6 @@ class Content extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{this.props.currentItem === 'database' &&
|
|
||||||
<UsersFilterBar
|
|
||||||
isActive={this.props.is_active}
|
|
||||||
role={this.props.role}
|
|
||||||
onStatusChange={this.props.onStatusChange}
|
|
||||||
onRoleChange={this.props.onRoleChange}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{items.length ? table : <EmptyTip text={gettext('No users')} />}
|
{items.length ? table : <EmptyTip text={gettext('No users')} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -201,12 +192,7 @@ Content.propTypes = {
|
|||||||
onUserSelected: PropTypes.func,
|
onUserSelected: PropTypes.func,
|
||||||
curPerPage: PropTypes.number,
|
curPerPage: PropTypes.number,
|
||||||
hasNextPage: PropTypes.bool,
|
hasNextPage: PropTypes.bool,
|
||||||
sortOrder: PropTypes.string,
|
sortOrder: PropTypes.string
|
||||||
is_active: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
||||||
role: PropTypes.string,
|
|
||||||
currentItem: PropTypes.string,
|
|
||||||
onStatusChange: PropTypes.func,
|
|
||||||
onRoleChange: PropTypes.func
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item extends Component {
|
class Item extends Component {
|
||||||
|
@ -1,29 +1,4 @@
|
|||||||
.users-filter-bar .users-filter-bar-dropdown-toggle {
|
.users-filter-bar .filter-item,
|
||||||
height: 30px;
|
.users-filter-bar .cur-option {
|
||||||
line-height: 30px;
|
|
||||||
padding-left: 8px;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.users-filter-bar .users-filter-bar-dropdown-toggle .sf3-font-down {
|
|
||||||
color: #999;
|
|
||||||
margin-left: auto;
|
|
||||||
display: inline-flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 12px;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.users-filter-bar .users-filter-bar-dropdown-toggle:hover {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.users-filter-bar .dropdown-menu .dropdown-item {
|
|
||||||
padding: 0.25rem 0.5rem;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
|
@ -1,117 +1,83 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Dropdown, DropdownToggle, DropdownItem, DropdownMenu } from 'reactstrap';
|
|
||||||
import { gettext } from '../../../utils/constants';
|
import { gettext } from '../../../utils/constants';
|
||||||
|
import Selector from '../../../components/single-selector';
|
||||||
import './users-filter-bar.css';
|
import './users-filter-bar.css';
|
||||||
|
|
||||||
const { availableRoles } = window.sysadmin.pageOptions;
|
const { availableRoles } = window.sysadmin.pageOptions;
|
||||||
|
|
||||||
class UsersFilterBar extends Component {
|
class UsersFilterBar extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
isStatusOpen: false,
|
|
||||||
isRoleOpen: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
translateStatus = (status) => {
|
|
||||||
switch (status) {
|
|
||||||
case '0':
|
|
||||||
return gettext('Inactive');
|
|
||||||
case '1':
|
|
||||||
return gettext('Active');
|
|
||||||
default:
|
|
||||||
return gettext('All');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
translateRole = (role) => {
|
translateRole = (role) => {
|
||||||
switch (role) {
|
switch (role) {
|
||||||
|
case '':
|
||||||
|
return gettext('All');
|
||||||
case 'default':
|
case 'default':
|
||||||
return gettext('Default');
|
return gettext('Default');
|
||||||
case 'guest':
|
case 'guest':
|
||||||
return gettext('Guest');
|
return gettext('Guest');
|
||||||
default:
|
default:
|
||||||
return gettext('All');
|
return role;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleStatusDropdown = () => {
|
selectStatusOption = (option) => {
|
||||||
this.setState({ isStatusOpen: !this.state.isStatusOpen });
|
this.props.onStatusChange(option.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleRoleDropdown = () => {
|
selectRoleOption = (option) => {
|
||||||
this.setState({ isRoleOpen: !this.state.isRoleOpen });
|
this.props.onRoleChange(option.value);
|
||||||
};
|
|
||||||
|
|
||||||
renderCheck = () => {
|
|
||||||
return <span className="sf2-icon-tick text-gray font-weight-bold"></span>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { onStatusChange, onRoleChange } = this.props;
|
const { isActive, role } = this.props;
|
||||||
|
|
||||||
|
this.statusOptions = [
|
||||||
|
{ value: '', text: gettext('All') },
|
||||||
|
{ value: '1', text: gettext('Active') },
|
||||||
|
{ value: '0', text: gettext('Inactive') }
|
||||||
|
].map(item => {
|
||||||
|
item.isSelected = isActive == item.value;
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
const currentSelectedStatusOption = this.statusOptions.filter(item => item.isSelected)[0];
|
||||||
|
|
||||||
|
this.roleOptions = [''].concat(availableRoles).map(item => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
text: this.translateRole(item),
|
||||||
|
isSelected: item == role
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const currentSelectedRoleOption = this.roleOptions.filter(item => item.isSelected)[0] || { // `|| {...}`: to be compatible with old data(roles not in the present `availableRoles`
|
||||||
|
value: role,
|
||||||
|
text: this.translateRole(role),
|
||||||
|
isSelected: true
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="users-filter-bar mt-4 mb-2 d-flex">
|
<div className="users-filter-bar mt-4 mb-2 d-flex align-items-center">
|
||||||
<Dropdown isOpen={this.state.isStatusOpen} toggle={this.toggleStatusDropdown}>
|
<span className="filter-item mr-2">{`${gettext('Status')}:`}</span>
|
||||||
<DropdownToggle
|
<Selector
|
||||||
tag="span"
|
isDropdownToggleShown={true}
|
||||||
data-toggle="dropdown"
|
currentSelectedOption={currentSelectedStatusOption}
|
||||||
aria-expanded={this.state.isStatusOpen}
|
options={this.statusOptions}
|
||||||
className="users-filter-bar-dropdown-toggle"
|
selectOption={this.selectStatusOption}
|
||||||
>
|
/>
|
||||||
<span>{gettext('Status')}{': '}{this.translateStatus(this.props.isActive)}</span>
|
|
||||||
<span className='sf3-font-down sf3-font'></span>
|
<span className="filter-item mr-2 ml-4">{`${gettext('Role')}:`}</span>
|
||||||
</DropdownToggle>
|
<Selector
|
||||||
<DropdownMenu>
|
isDropdownToggleShown={true}
|
||||||
<DropdownItem key={0} onClick={() => { onStatusChange(''); }}>
|
currentSelectedOption={currentSelectedRoleOption}
|
||||||
<span>{gettext('All')}</span>{this.props.isActive === '' && this.renderCheck()}
|
options={this.roleOptions}
|
||||||
</DropdownItem>
|
selectOption={this.selectRoleOption}
|
||||||
<DropdownItem key={1} onClick={() => { onStatusChange('1'); }}>
|
/>
|
||||||
<span>{gettext('Active')}</span>{this.props.isActive === '1' && this.renderCheck()}
|
|
||||||
</DropdownItem>
|
|
||||||
<DropdownItem key={2} onClick={() => { onStatusChange('0'); }}>
|
|
||||||
<span>{gettext('Inactive')}</span>{this.props.isActive === '0' && this.renderCheck()}
|
|
||||||
</DropdownItem>
|
|
||||||
</DropdownMenu>
|
|
||||||
</Dropdown>
|
|
||||||
<Dropdown isOpen={this.state.isRoleOpen} toggle={this.toggleRoleDropdown} className="ml-4">
|
|
||||||
<DropdownToggle
|
|
||||||
tag="span"
|
|
||||||
data-toggle="dropdown"
|
|
||||||
aria-expanded={this.state.isRoleOpen}
|
|
||||||
className="users-filter-bar-dropdown-toggle"
|
|
||||||
>
|
|
||||||
<span>{gettext('Role')}{': '}{this.translateRole(this.props.role)}</span>
|
|
||||||
<span className='sf3-font-down sf3-font'></span>
|
|
||||||
</DropdownToggle>
|
|
||||||
<DropdownMenu>
|
|
||||||
<DropdownItem key={0} onClick={() => { onRoleChange(''); }}>
|
|
||||||
<span>{gettext('All')}</span>
|
|
||||||
{this.props.role === '' && this.renderCheck()}
|
|
||||||
</DropdownItem>
|
|
||||||
{availableRoles.map((item, index) => {
|
|
||||||
return (
|
|
||||||
<DropdownItem key={index} onClick={() => { onRoleChange(item); }}>
|
|
||||||
<span>{this.translateRole(item)}</span>
|
|
||||||
{this.props.role === item && this.renderCheck()}
|
|
||||||
</DropdownItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</DropdownMenu>
|
|
||||||
</Dropdown>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UsersFilterBar.propTypes = {
|
UsersFilterBar.propTypes = {
|
||||||
loading: PropTypes.bool,
|
|
||||||
curPerPage: PropTypes.number,
|
|
||||||
sortBy: PropTypes.string,
|
|
||||||
currentPage: PropTypes.number,
|
|
||||||
sortOrder: PropTypes.string,
|
|
||||||
onStatusChange: PropTypes.func,
|
onStatusChange: PropTypes.func,
|
||||||
onRoleChange: PropTypes.func,
|
onRoleChange: PropTypes.func,
|
||||||
role: PropTypes.string,
|
role: PropTypes.string,
|
||||||
|
@ -16,6 +16,7 @@ import SysAdminAdminUser from '../../../models/sysadmin-admin-user';
|
|||||||
import MainPanelTopbar from '../main-panel-topbar';
|
import MainPanelTopbar from '../main-panel-topbar';
|
||||||
import Search from '../search';
|
import Search from '../search';
|
||||||
import UsersNav from './users-nav';
|
import UsersNav from './users-nav';
|
||||||
|
import UsersFilterBar from './users-filter-bar';
|
||||||
import Content from './users-content';
|
import Content from './users-content';
|
||||||
|
|
||||||
const { availableRoles } = window.sysadmin.pageOptions;
|
const { availableRoles } = window.sysadmin.pageOptions;
|
||||||
@ -44,8 +45,8 @@ class Users extends Component {
|
|||||||
isBatchSetQuotaDialogOpen: false,
|
isBatchSetQuotaDialogOpen: false,
|
||||||
isBatchDeleteUserDialogOpen: false,
|
isBatchDeleteUserDialogOpen: false,
|
||||||
isBatchAddAdminDialogOpen: false,
|
isBatchAddAdminDialogOpen: false,
|
||||||
is_active: null,
|
is_active: '',
|
||||||
role: null,
|
role: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,15 +60,17 @@ class Users extends Component {
|
|||||||
sortBy = '',
|
sortBy = '',
|
||||||
sortOrder = 'asc',
|
sortOrder = 'asc',
|
||||||
is_active,
|
is_active,
|
||||||
role,
|
role
|
||||||
} = this.state;
|
} = this.state;
|
||||||
this.setState({
|
this.setState({
|
||||||
perPage: parseInt(urlParams.get('per_page') || perPage),
|
perPage: parseInt(urlParams.get('per_page') || perPage),
|
||||||
currentPage: parseInt(urlParams.get('page') || currentPage),
|
currentPage: parseInt(urlParams.get('page') || currentPage),
|
||||||
sortBy: urlParams.get('order_by') || sortBy,
|
sortBy: urlParams.get('order_by') || sortBy,
|
||||||
sortOrder: urlParams.get('direction') || sortOrder,
|
sortOrder: urlParams.get('direction') || sortOrder,
|
||||||
|
is_active: urlParams.get('is_active') || is_active,
|
||||||
|
role: urlParams.get('role') || role
|
||||||
}, () => {
|
}, () => {
|
||||||
this.getUsersListByPage(this.state.currentPage, is_active, role);
|
this.getUsersListByPage(this.state.currentPage);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,8 +167,8 @@ class Users extends Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
getUsersListByPage = (page, is_active, role) => {
|
getUsersListByPage = (page) => {
|
||||||
const { perPage, sortBy, sortOrder } = this.state;
|
const { perPage, sortBy, sortOrder, is_active, role } = this.state;
|
||||||
const { isLDAPImported } = this.props;
|
const { isLDAPImported } = this.props;
|
||||||
systemAdminAPI.sysAdminListUsers(page, perPage, isLDAPImported, sortBy, sortOrder, is_active, role).then(res => {
|
systemAdminAPI.sysAdminListUsers(page, perPage, isLDAPImported, sortBy, sortOrder, is_active, role).then(res => {
|
||||||
let users = res.data.data.map(user => {return new SysAdminUser(user);});
|
let users = res.data.data.map(user => {return new SysAdminUser(user);});
|
||||||
@ -183,11 +186,12 @@ class Users extends Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateURL = (page, perPage) => {
|
updateURLSearchParams = (obj) => {
|
||||||
let url = new URL(location.href);
|
let url = new URL(location.href);
|
||||||
let searchParams = new URLSearchParams(url.search);
|
let searchParams = new URLSearchParams(url.search);
|
||||||
searchParams.set('page', page);
|
for (const key in obj) {
|
||||||
searchParams.set('per_page', perPage);
|
searchParams.set(key, obj[key]);
|
||||||
|
}
|
||||||
url.search = searchParams.toString();
|
url.search = searchParams.toString();
|
||||||
navigate(url.toString());
|
navigate(url.toString());
|
||||||
};
|
};
|
||||||
@ -198,21 +202,28 @@ class Users extends Component {
|
|||||||
is_active: is_active,
|
is_active: is_active,
|
||||||
currentPage: 1
|
currentPage: 1
|
||||||
}, () => {
|
}, () => {
|
||||||
const { currentPage, perPage, is_active, role } = this.state;
|
const { currentPage, perPage } = this.state;
|
||||||
this.updateURL(currentPage, perPage);
|
this.updateURLSearchParams({
|
||||||
this.getUsersListByPage(currentPage, is_active, role);
|
'page': currentPage,
|
||||||
|
'per_page': perPage,
|
||||||
|
'is_active': is_active
|
||||||
|
});
|
||||||
|
this.getUsersListByPage(currentPage);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// role: 'default', 'guest', ''
|
|
||||||
onRoleChange = (role) => {
|
onRoleChange = (role) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
role: role,
|
role: role,
|
||||||
currentPage: 1
|
currentPage: 1
|
||||||
}, () => {
|
}, () => {
|
||||||
const { currentPage, perPage, is_active, role } = this.state;
|
const { currentPage, perPage } = this.state;
|
||||||
this.updateURL(currentPage, perPage);
|
this.updateURLSearchParams({
|
||||||
this.getUsersListByPage(currentPage, is_active, role);
|
'page': currentPage,
|
||||||
|
'per_page': perPage,
|
||||||
|
'role': role
|
||||||
|
});
|
||||||
|
this.getUsersListByPage(currentPage);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -222,15 +233,14 @@ class Users extends Component {
|
|||||||
sortOrder: this.state.sortOrder == 'asc' ? 'desc' : 'asc',
|
sortOrder: this.state.sortOrder == 'asc' ? 'desc' : 'asc',
|
||||||
currentPage: 1
|
currentPage: 1
|
||||||
}, () => {
|
}, () => {
|
||||||
let url = new URL(location.href);
|
const { currentPage, perPage, sortBy, sortOrder } = this.state;
|
||||||
let searchParams = new URLSearchParams(url.search);
|
this.updateURLSearchParams({
|
||||||
const { currentPage, sortBy, sortOrder, is_active, role } = this.state;
|
'page': currentPage,
|
||||||
searchParams.set('page', currentPage);
|
'per_page': perPage,
|
||||||
searchParams.set('order_by', sortBy);
|
'order_by': sortBy,
|
||||||
searchParams.set('direction', sortOrder);
|
'direction': sortOrder
|
||||||
url.search = searchParams.toString();
|
});
|
||||||
navigate(url.toString());
|
this.getUsersListByPage(currentPage);
|
||||||
this.getUsersListByPage(currentPage, is_active, role);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -346,7 +356,7 @@ class Users extends Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
perPage: perPage
|
perPage: perPage
|
||||||
}, () => {
|
}, () => {
|
||||||
this.getUsersListByPage(1, this.state.is_active, this.state.role);
|
this.getUsersListByPage(1);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -471,6 +481,8 @@ class Users extends Component {
|
|||||||
render() {
|
render() {
|
||||||
const { isAdmin, isLDAPImported } = this.props;
|
const { isAdmin, isLDAPImported } = this.props;
|
||||||
const {
|
const {
|
||||||
|
is_active,
|
||||||
|
role,
|
||||||
hasUserSelected,
|
hasUserSelected,
|
||||||
isImportUserDialogOpen,
|
isImportUserDialogOpen,
|
||||||
isAddUserDialogOpen,
|
isAddUserDialogOpen,
|
||||||
@ -478,6 +490,7 @@ class Users extends Component {
|
|||||||
isBatchSetQuotaDialogOpen,
|
isBatchSetQuotaDialogOpen,
|
||||||
isBatchAddAdminDialogOpen
|
isBatchAddAdminDialogOpen
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
const curTab = this.getCurrentNavItem();
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<MainPanelTopbar search={this.getSearch()} {...this.props}>
|
<MainPanelTopbar search={this.getSearch()} {...this.props}>
|
||||||
@ -491,8 +504,16 @@ class Users extends Component {
|
|||||||
</MainPanelTopbar>
|
</MainPanelTopbar>
|
||||||
<div className="main-panel-center flex-row">
|
<div className="main-panel-center flex-row">
|
||||||
<div className="cur-view-container">
|
<div className="cur-view-container">
|
||||||
<UsersNav currentItem={this.getCurrentNavItem()} />
|
<UsersNav currentItem={curTab} />
|
||||||
<div className="cur-view-content">
|
<div className="cur-view-content">
|
||||||
|
{curTab == 'database' &&
|
||||||
|
<UsersFilterBar
|
||||||
|
isActive={is_active}
|
||||||
|
role={role}
|
||||||
|
onStatusChange={this.onStatusChange}
|
||||||
|
onRoleChange={this.onRoleChange}
|
||||||
|
/>
|
||||||
|
}
|
||||||
<Content
|
<Content
|
||||||
isAdmin={isAdmin}
|
isAdmin={isAdmin}
|
||||||
isLDAPImported={isLDAPImported}
|
isLDAPImported={isLDAPImported}
|
||||||
@ -505,8 +526,6 @@ class Users extends Component {
|
|||||||
currentPage={this.state.currentPage}
|
currentPage={this.state.currentPage}
|
||||||
hasNextPage={this.state.hasNextPage}
|
hasNextPage={this.state.hasNextPage}
|
||||||
curPerPage={this.state.perPage}
|
curPerPage={this.state.perPage}
|
||||||
is_active={this.state.is_active}
|
|
||||||
role={this.state.role}
|
|
||||||
resetPerPage={this.resetPerPage}
|
resetPerPage={this.resetPerPage}
|
||||||
getListByPage={this.getUsersListByPage}
|
getListByPage={this.getUsersListByPage}
|
||||||
updateUser={this.updateUser}
|
updateUser={this.updateUser}
|
||||||
@ -516,9 +535,6 @@ class Users extends Component {
|
|||||||
onUserSelected={this.onUserSelected}
|
onUserSelected={this.onUserSelected}
|
||||||
isAllUsersSelected={this.isAllUsersSelected}
|
isAllUsersSelected={this.isAllUsersSelected}
|
||||||
toggleSelectAllUsers={this.toggleSelectAllUsers}
|
toggleSelectAllUsers={this.toggleSelectAllUsers}
|
||||||
onRoleChange={this.onRoleChange}
|
|
||||||
onStatusChange={this.onStatusChange}
|
|
||||||
currentItem={this.getCurrentNavItem()}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1259,6 +1259,9 @@ pidfile = os.path.join(pids_dir, 'seahub.pid')
|
|||||||
timeout = 1200
|
timeout = 1200
|
||||||
|
|
||||||
limit_request_line = 8190
|
limit_request_line = 8190
|
||||||
|
|
||||||
|
# for forwarder headers
|
||||||
|
forwarder_headers = 'SCRIPT_NAME,PATH_INFO,REMOTE_USER'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
text = template % dict(pids_dir=env_mgr.central_pids_dir,
|
text = template % dict(pids_dir=env_mgr.central_pids_dir,
|
||||||
|
Loading…
Reference in New Issue
Block a user