mirror of
https://github.com/haiwen/seahub.git
synced 2025-04-26 18:40:53 +00:00
[group] added full operation menus for all the department/group items… (#7706)
* [group] added full operation menus for all the department/group items in 'Files' page; fixed & improved all the operations * remove useless state * fix test lib --------- Co-authored-by: Michael An <1822852997@qq.com>
This commit is contained in:
parent
baddc4bad7
commit
cf262f09db
1
.github/workflows/test.yml
vendored
1
.github/workflows/test.yml
vendored
@ -25,6 +25,7 @@ jobs:
|
||||
sudo apt-get install -y libfuse-dev cmake re2c flex sqlite3
|
||||
sudo apt-get install -y libssl-dev libsasl2-dev libldap2-dev libonig-dev
|
||||
sudo apt-get install -y libxml2 libxml2-dev libjwt-dev
|
||||
sudo apt-get install -y libhiredis-dev
|
||||
|
||||
- name: clone and build
|
||||
run: |
|
||||
|
@ -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) => {
|
||||
let pathPrefix = [];
|
||||
if (groupID || this.dirViewPanels.indexOf(tabName) > -1) {
|
||||
@ -343,7 +330,7 @@ class App extends Component {
|
||||
<InvitationsView path={siteRoot + 'invitations/'} />
|
||||
<FilesActivities path={siteRoot + 'dashboard'} />
|
||||
<MyFileActivities path={siteRoot + 'my-activities'} />
|
||||
<GroupView path={siteRoot + 'group/:groupID'} onGroupChanged={this.onGroupChanged} />
|
||||
<GroupView path={siteRoot + 'group/:groupID'} />
|
||||
<LinkedDevices path={siteRoot + 'linked-devices'} />
|
||||
<ShareAdminLibraries path={siteRoot + 'share-admin-libs'} />
|
||||
<ShareAdminFolders path={siteRoot + 'share-admin-folders'} />
|
||||
|
@ -9,14 +9,11 @@ import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
||||
|
||||
class DismissGroupDialog extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
dismissGroup = () => {
|
||||
let that = this;
|
||||
seafileAPI.deleteGroup(this.props.groupID).then((res) => {
|
||||
that.props.onGroupChanged();
|
||||
const { groupID } = this.props;
|
||||
seafileAPI.deleteGroup(groupID).then((res) => {
|
||||
this.props.onGroupDeleted();
|
||||
toaster.success(gettext('Group deleted'));
|
||||
}).catch(error => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
toaster.danger(errMessage);
|
||||
@ -25,13 +22,13 @@ class DismissGroupDialog extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Modal isOpen={this.props.showDismissGroupDialog} toggle={this.props.toggleDismissGroupDialog}>
|
||||
<SeahubModalHeader>{gettext('Delete Group')}</SeahubModalHeader>
|
||||
<Modal isOpen={true} toggle={this.props.toggleDialog}>
|
||||
<SeahubModalHeader toggle={this.props.toggleDialog}>{gettext('Delete Group')}</SeahubModalHeader>
|
||||
<ModalBody>
|
||||
<span>{gettext('Really want to delete this group?')}</span>
|
||||
</ModalBody>
|
||||
<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>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
@ -40,11 +37,9 @@ class DismissGroupDialog extends React.Component {
|
||||
}
|
||||
|
||||
const DismissGroupDialogPropTypes = {
|
||||
showDismissGroupDialog: PropTypes.bool.isRequired,
|
||||
toggleDismissGroupDialog: PropTypes.func.isRequired,
|
||||
loadGroup: PropTypes.func.isRequired,
|
||||
groupID: PropTypes.string,
|
||||
onGroupChanged: PropTypes.func.isRequired,
|
||||
groupID: PropTypes.number.isRequired,
|
||||
toggleDialog: PropTypes.func.isRequired,
|
||||
onGroupDeleted: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
DismissGroupDialog.propTypes = DismissGroupDialogPropTypes;
|
||||
|
@ -9,7 +9,7 @@ import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
||||
import Loading from '../loading';
|
||||
|
||||
const propTypes = {
|
||||
groupID: PropTypes.string.isRequired,
|
||||
groupID: PropTypes.number.isRequired,
|
||||
toggleDialog: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { gettext, siteRoot, groupImportMembersExtraMsg } from '../../utils/const
|
||||
import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
||||
|
||||
const propTypes = {
|
||||
toggleImportMembersDialog: PropTypes.func.isRequired,
|
||||
toggleDialog: PropTypes.func.isRequired,
|
||||
importMembersInBatch: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
@ -19,7 +19,7 @@ class ImportMembersDialog extends React.Component {
|
||||
}
|
||||
|
||||
toggle = () => {
|
||||
this.props.toggleImportMembersDialog();
|
||||
this.props.toggleDialog();
|
||||
};
|
||||
|
||||
openFileInput = () => {
|
||||
@ -49,9 +49,8 @@ class ImportMembersDialog extends React.Component {
|
||||
return (
|
||||
<Modal isOpen={true} toggle={this.toggle}>
|
||||
<SeahubModalHeader toggle={this.toggle}>{gettext('Import members from a .xlsx file')}</SeahubModalHeader>
|
||||
|
||||
<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>
|
||||
<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} />
|
||||
|
@ -9,13 +9,10 @@ import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
||||
|
||||
class LeaveGroupDialog extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
leaveGroup = () => {
|
||||
seafileAPI.quitGroup(this.props.groupID, username).then((res) => {
|
||||
this.props.onGroupChanged();
|
||||
const { groupID } = this.props;
|
||||
seafileAPI.quitGroup(groupID, username).then((res) => {
|
||||
this.props.onLeavingGroup();
|
||||
}).catch(error => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
toaster.danger(errMessage);
|
||||
@ -24,13 +21,13 @@ class LeaveGroupDialog extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Modal isOpen={true} toggle={this.props.toggleLeaveGroupDialog}>
|
||||
<SeahubModalHeader toggle={this.props.toggleLeaveGroupDialog}>{gettext('Leave Group')}</SeahubModalHeader>
|
||||
<Modal isOpen={true} toggle={this.props.toggleDialog}>
|
||||
<SeahubModalHeader toggle={this.props.toggleDialog}>{gettext('Leave Group')}</SeahubModalHeader>
|
||||
<ModalBody>
|
||||
<p>{gettext('Really want to leave this group?')}</p>
|
||||
</ModalBody>
|
||||
<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>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
@ -39,9 +36,9 @@ class LeaveGroupDialog extends React.Component {
|
||||
}
|
||||
|
||||
const LeaveGroupDialogPropTypes = {
|
||||
toggleLeaveGroupDialog: PropTypes.func.isRequired,
|
||||
groupID: PropTypes.string,
|
||||
onGroupChanged: PropTypes.func.isRequired,
|
||||
groupID: PropTypes.number.isRequired,
|
||||
onLeavingGroup: PropTypes.func.isRequired,
|
||||
toggleDialog: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
LeaveGroupDialog.propTypes = LeaveGroupDialogPropTypes;
|
||||
|
@ -8,7 +8,7 @@ import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
||||
import '../../css/manage-members-dialog.css';
|
||||
|
||||
const propTypes = {
|
||||
groupID: PropTypes.string,
|
||||
groupID: PropTypes.number.isRequired,
|
||||
isOwner: PropTypes.bool.isRequired,
|
||||
toggleManageMembersDialog: PropTypes.func,
|
||||
toggleDepartmentDetailDialog: PropTypes.func,
|
||||
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import { gettext } from '../../utils/constants';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
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 toaster from '../toast';
|
||||
|
||||
@ -12,7 +12,7 @@ class RenameGroupDialog extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
newGroupName: this.props.currentGroupName,
|
||||
newGroupName: this.props.groupName,
|
||||
isSubmitBtnActive: false,
|
||||
};
|
||||
}
|
||||
@ -30,48 +30,42 @@ class RenameGroupDialog extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
renameGroup = () => {
|
||||
let name = this.state.newGroupName.trim();
|
||||
if (name) {
|
||||
let that = this;
|
||||
seafileAPI.renameGroup(this.props.groupID, name).then((res) => {
|
||||
that.props.loadGroup(this.props.groupID);
|
||||
that.props.onGroupChanged(res.data.id);
|
||||
}).catch(error => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
toaster.danger(errMessage);
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
newGroupName: '',
|
||||
handleSubmit = () => {
|
||||
const { groupID } = this.props;
|
||||
const { newGroupName } = this.state;
|
||||
seafileAPI.renameGroup(groupID, newGroupName.trim()).then((res) => {
|
||||
const { name } = res.data;
|
||||
this.props.onGroupNameChanged(name);
|
||||
}).catch(error => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
toaster.danger(errMessage);
|
||||
});
|
||||
this.props.toggleRenameGroupDialog();
|
||||
this.props.toggleDialog();
|
||||
};
|
||||
|
||||
handleKeyDown = (event) => {
|
||||
if (event.keyCode === 13) {
|
||||
this.renameGroup();
|
||||
this.handleSubmit();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Modal isOpen={this.props.showRenameGroupDialog} toggle={this.props.toggleRenameGroupDialog}>
|
||||
<SeahubModalHeader>{gettext('Rename Group')}</SeahubModalHeader>
|
||||
<Modal isOpen={true} toggle={this.props.toggleDialog}>
|
||||
<SeahubModalHeader toggle={this.props.toggleDialog}>{gettext('Rename Group')}</SeahubModalHeader>
|
||||
<ModalBody>
|
||||
<label htmlFor="newGroupName">{gettext('Rename group to')}</label>
|
||||
<Label for="group-name">{gettext('Rename group to')}</Label>
|
||||
<Input
|
||||
type="text"
|
||||
id="newGroupName"
|
||||
name="new-group-name"
|
||||
id="group-name"
|
||||
value={this.state.newGroupName}
|
||||
onChange={this.handleGroupNameChange}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
/>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="secondary" onClick={this.props.toggleRenameGroupDialog}>{gettext('Cancel')}</Button>
|
||||
<Button color="primary" onClick={this.renameGroup} disabled={!this.state.isSubmitBtnActive}>{gettext('Submit')}</Button>
|
||||
<Button color="secondary" onClick={this.props.toggleDialog}>{gettext('Cancel')}</Button>
|
||||
<Button color="primary" onClick={this.handleSubmit} disabled={!this.state.isSubmitBtnActive}>{gettext('Submit')}</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
);
|
||||
@ -79,12 +73,10 @@ class RenameGroupDialog extends React.Component {
|
||||
}
|
||||
|
||||
const RenameGroupDialogPropTypes = {
|
||||
showRenameGroupDialog: PropTypes.bool.isRequired,
|
||||
toggleRenameGroupDialog: PropTypes.func.isRequired,
|
||||
loadGroup: PropTypes.func.isRequired,
|
||||
groupID: PropTypes.string,
|
||||
onGroupChanged: PropTypes.func.isRequired,
|
||||
currentGroupName: PropTypes.string.isRequired,
|
||||
toggleDialog: PropTypes.func.isRequired,
|
||||
groupID: PropTypes.number,
|
||||
onGroupNameChanged: PropTypes.func.isRequired,
|
||||
groupName: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
RenameGroupDialog.propTypes = RenameGroupDialogPropTypes;
|
||||
|
@ -11,9 +11,9 @@ import toaster from '../toast';
|
||||
import '../../css/transfer-group-dialog.css';
|
||||
|
||||
const propTypes = {
|
||||
groupID: PropTypes.string,
|
||||
toggleTransferGroupDialog: PropTypes.func.isRequired,
|
||||
onGroupChanged: PropTypes.func.isRequired
|
||||
groupID: PropTypes.number.isRequired,
|
||||
onGroupTransfered: PropTypes.func.isRequired,
|
||||
toggleDialog: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
class TransferGroupDialog extends React.Component {
|
||||
@ -21,18 +21,14 @@ class TransferGroupDialog extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selectedOption: null,
|
||||
errMessage: '',
|
||||
selectedOption: null
|
||||
};
|
||||
this.options = [];
|
||||
}
|
||||
|
||||
handleSelectChange = (option) => {
|
||||
this.setState({
|
||||
selectedOption: option,
|
||||
errMessage: '',
|
||||
selectedOption: option
|
||||
});
|
||||
this.options = [];
|
||||
};
|
||||
|
||||
transferGroup = () => {
|
||||
@ -41,19 +37,21 @@ class TransferGroupDialog extends React.Component {
|
||||
if (selectedOption && selectedOption[0]) {
|
||||
email = selectedOption[0].email;
|
||||
}
|
||||
if (email) {
|
||||
seafileAPI.transferGroup(this.props.groupID, email).then((res) => {
|
||||
this.props.toggleTransferGroupDialog();
|
||||
toaster.success(gettext('Group has been transfered'));
|
||||
}).catch((error) => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
this.setState({ errMessage: errMessage });
|
||||
});
|
||||
if (!email) {
|
||||
return false;
|
||||
}
|
||||
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 = () => {
|
||||
this.props.toggleTransferGroupDialog();
|
||||
this.props.toggleDialog();
|
||||
};
|
||||
|
||||
render() {
|
||||
@ -68,7 +66,6 @@ class TransferGroupDialog extends React.Component {
|
||||
placeholder={gettext('Please enter 1 or more character')}
|
||||
onSelectChange={this.handleSelectChange}
|
||||
/>
|
||||
<div className="error">{this.state.errMessage}</div>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="secondary" onClick={this.toggle}>{gettext('Close')}</Button>
|
||||
|
@ -10,7 +10,7 @@ import OpIcon from './op-icon';
|
||||
|
||||
const propTypes = {
|
||||
groupMembers: PropTypes.array.isRequired,
|
||||
groupID: PropTypes.string,
|
||||
groupID: PropTypes.number.isRequired,
|
||||
isOwner: PropTypes.bool.isRequired,
|
||||
isItemFreezed: PropTypes.bool.isRequired,
|
||||
toggleItemFreezed: PropTypes.func.isRequired,
|
||||
@ -61,7 +61,7 @@ const MemberPropTypes = {
|
||||
changeMember: PropTypes.func.isRequired,
|
||||
deleteMember: PropTypes.func.isRequired,
|
||||
toggleItemFreezed: PropTypes.func.isRequired,
|
||||
groupID: PropTypes.string,
|
||||
groupID: PropTypes.number.isRequired,
|
||||
isOwner: PropTypes.bool.isRequired,
|
||||
isItemFreezed: PropTypes.bool.isRequired
|
||||
};
|
||||
|
@ -12,7 +12,7 @@ import GroupMembers from './group-members';
|
||||
const propTypes = {
|
||||
toggleManageMembersDialog: PropTypes.func,
|
||||
toggleDepartmentDetailDialog: PropTypes.func,
|
||||
groupID: PropTypes.string,
|
||||
groupID: PropTypes.number.isRequired,
|
||||
isOwner: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
import React from 'react';
|
||||
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 { Utils } from '../../utils/utils';
|
||||
import toaster from '../../components/toast';
|
||||
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 GroupOperationMenu from './group-op-menu';
|
||||
|
||||
const propTypes = {
|
||||
inAllLibs: PropTypes.bool,
|
||||
@ -17,21 +15,18 @@ const propTypes = {
|
||||
onMonitorRepo: PropTypes.func,
|
||||
renameRelatedGroupsRepos: PropTypes.func,
|
||||
deleteRelatedGroupsRepos: PropTypes.func,
|
||||
insertRepoIntoGroup: PropTypes.func,
|
||||
addRepoToGroup: PropTypes.func,
|
||||
unshareRepoToGroup: PropTypes.func,
|
||||
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 {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isCreateRepoDialogOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
onItemUnshare = (repo) => {
|
||||
const { group } = this.props;
|
||||
const { id: group_id } = group;
|
||||
@ -61,53 +56,45 @@ class GroupItem extends React.Component {
|
||||
this.props.onMonitorRepo(repo, monitored);
|
||||
};
|
||||
|
||||
toggleCreateRepoDialog = () => {
|
||||
this.setState({
|
||||
isCreateRepoDialogOpen: !this.state.isCreateRepoDialogOpen
|
||||
});
|
||||
};
|
||||
|
||||
onCreateRepo = (repo) => {
|
||||
addNewRepo = (newRepo) => {
|
||||
const { group } = this.props;
|
||||
const { id: group_id } = group;
|
||||
seafileAPI.createGroupOwnedLibrary(group_id, 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 newRepo = new Repo(object);
|
||||
this.props.insertRepoIntoGroup({ repo: newRepo, group_id });
|
||||
}).catch(error => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
toaster.danger(errMessage);
|
||||
});
|
||||
this.toggleCreateRepoDialog();
|
||||
this.props.addRepoToGroup({ repo: newRepo, group_id });
|
||||
};
|
||||
|
||||
onGroupNameChanged = (newName) => {
|
||||
const { group } = this.props;
|
||||
this.props.onGroupNameChanged(newName, group.id);
|
||||
};
|
||||
|
||||
onGroupDeleted = () => {
|
||||
const { group } = this.props;
|
||||
this.props.onGroupDeleted(group.id);
|
||||
};
|
||||
|
||||
onLeavingGroup = () => {
|
||||
const { group } = this.props;
|
||||
this.props.onLeavingGroup(group.id);
|
||||
};
|
||||
|
||||
render() {
|
||||
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 isDeptAdmin = parent_group_id != 0 && admins.indexOf(username) > -1;
|
||||
return (
|
||||
<div className="pb-3">
|
||||
<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">
|
||||
<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>
|
||||
{isDeptAdmin &&
|
||||
<SingleDropdownToolbar
|
||||
withPlusIcon={true}
|
||||
opList={[{ 'text': gettext('New Library'), 'onClick': this.toggleCreateRepoDialog }]}
|
||||
/>
|
||||
}
|
||||
<GroupOperationMenu
|
||||
group={group}
|
||||
addNewRepo={this.addNewRepo}
|
||||
onGroupNameChanged={this.onGroupNameChanged}
|
||||
onGroupTransfered={this.props.onGroupTransfered}
|
||||
onGroupDeleted={this.onGroupDeleted}
|
||||
onLeavingGroup={this.onLeavingGroup}
|
||||
/>
|
||||
</h4>
|
||||
</div>
|
||||
{group.repos.length === 0 ?
|
||||
@ -127,13 +114,6 @@ class GroupItem extends React.Component {
|
||||
currentViewMode={currentViewMode}
|
||||
/>
|
||||
}
|
||||
{this.state.isCreateRepoDialogOpen &&
|
||||
<CreateRepoDialog
|
||||
onCreateToggle={this.toggleCreateRepoDialog}
|
||||
onCreateRepo={this.onCreateRepo}
|
||||
libraryType='department'
|
||||
/>
|
||||
}
|
||||
</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,35 +2,25 @@ import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cookie from 'react-cookies';
|
||||
import classnames from 'classnames';
|
||||
import { gettext, username, canAddRepo } from '../../utils/constants';
|
||||
import { navigate } from '@gatsbyjs/reach-router';
|
||||
import { gettext, siteRoot, username } from '../../utils/constants';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import Loading from '../../components/loading';
|
||||
import EmptyTip from '../../components/empty-tip';
|
||||
import ModalPortal from '../../components/modal-portal';
|
||||
import toaster from '../../components/toast';
|
||||
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 SortOptionsDialog from '../../components/dialog/sort-options';
|
||||
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
|
||||
import ViewModes from '../../components/view-modes';
|
||||
import ReposSortMenu from '../../components/sort-menu';
|
||||
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
||||
import GroupOperationMenu from './group-op-menu';
|
||||
|
||||
import '../../css/group-view.css';
|
||||
|
||||
const propTypes = {
|
||||
onGroupChanged: PropTypes.func.isRequired,
|
||||
groupID: PropTypes.string,
|
||||
groupID: PropTypes.string
|
||||
};
|
||||
|
||||
class GroupView extends React.Component {
|
||||
@ -43,9 +33,6 @@ class GroupView extends React.Component {
|
||||
errMessage: '',
|
||||
emptyTip: null,
|
||||
currentGroup: null,
|
||||
currentRepo: null,
|
||||
isStaff: false,
|
||||
isOwner: false,
|
||||
currentViewMode: localStorage.getItem('sf_repo_list_view_mode') || LIST_MODE,
|
||||
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'
|
||||
@ -54,19 +41,7 @@ class GroupView extends React.Component {
|
||||
currentPage: 1,
|
||||
perPage: 300,
|
||||
hasNextPage: false,
|
||||
libraryType: 'group',
|
||||
isCreateRepoDialogShow: false,
|
||||
isDepartmentGroup: false,
|
||||
isShowDepartmentDetailDialog: false,
|
||||
showGroupDropdown: false,
|
||||
showGroupMembersPopover: false,
|
||||
showRenameGroupDialog: false,
|
||||
showDismissGroupDialog: false,
|
||||
showTransferGroupDialog: false,
|
||||
showImportMembersDialog: false,
|
||||
showManageMembersDialog: false,
|
||||
isLeaveGroupDialogOpen: false,
|
||||
isMembersDialogOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
@ -86,9 +61,7 @@ class GroupView extends React.Component {
|
||||
this.setState({
|
||||
emptyTip: this.getEmptyTip(currentGroup),
|
||||
currentGroup,
|
||||
isStaff: currentGroup.admins.indexOf(username) > -1, // for item operations
|
||||
isDepartmentGroup: currentGroup.parent_group_id !== 0,
|
||||
isOwner: currentGroup.owner === username,
|
||||
currentPage: 1,
|
||||
repoList: [] // empty it for the current group
|
||||
}, () => {
|
||||
@ -160,45 +133,6 @@ class GroupView extends React.Component {
|
||||
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) => {
|
||||
let repoList = this.state.repoList.filter(item => {
|
||||
return item.repo_id !== repo.repo_id;
|
||||
@ -215,12 +149,6 @@ class GroupView extends React.Component {
|
||||
this.loadGroup(this.props.groupID);
|
||||
};
|
||||
|
||||
addRepoItem = (repo) => {
|
||||
let newRepoList = this.state.repoList.map(item => {return item;});
|
||||
newRepoList.unshift(repo);
|
||||
return newRepoList;
|
||||
};
|
||||
|
||||
onItemUnshare = (repo) => {
|
||||
let group = this.state.currentGroup;
|
||||
seafileAPI.unshareRepoToGroup(repo.repo_id, group.id).then(() => {
|
||||
@ -260,59 +188,6 @@ class GroupView extends React.Component {
|
||||
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
|
||||
});
|
||||
};
|
||||
|
||||
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) => {
|
||||
cookie.save('seafile-repo-dir-sort-by', sortBy);
|
||||
cookie.save('seafile-repo-dir-sort-order', sortOrder);
|
||||
@ -323,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 = () => {
|
||||
this.setState({
|
||||
isSortOptionsDialogOpen: !this.state.isSortOptionsDialogOpen
|
||||
@ -357,43 +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 });
|
||||
}
|
||||
}
|
||||
|
||||
return opList;
|
||||
};
|
||||
|
||||
switchViewMode = (newMode) => {
|
||||
this.setState({
|
||||
currentViewMode: newMode
|
||||
@ -409,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({
|
||||
isShowDepartmentDetailDialog: !this.state.isShowDepartmentDetailDialog
|
||||
currentGroup: currentGroup
|
||||
});
|
||||
};
|
||||
|
||||
onGroupTransfered = (group) => {
|
||||
this.setState({
|
||||
currentGroup: group
|
||||
});
|
||||
};
|
||||
|
||||
onGroupDeleted = () => {
|
||||
navigate(siteRoot);
|
||||
};
|
||||
|
||||
onLeavingGroup = () => {
|
||||
navigate(siteRoot);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
isLoading, repoList, errMessage, emptyTip,
|
||||
currentGroup, isDepartmentGroup, isMembersDialogOpen,
|
||||
currentGroup, isDepartmentGroup,
|
||||
currentViewMode, sortBy, sortOrder
|
||||
} = this.state;
|
||||
|
||||
@ -427,7 +275,6 @@ class GroupView extends React.Component {
|
||||
useRate = currentGroup.group_quota_usage / currentGroup.group_quota * 100 + '%';
|
||||
}
|
||||
|
||||
const opList = this.getOpList();
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="main-panel-center flex-row">
|
||||
@ -440,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>{currentGroup.name}</span>
|
||||
<SingleDropdownToolbar
|
||||
withPlusIcon={this.newLibraryEnalbed}
|
||||
opList={opList}
|
||||
<GroupOperationMenu
|
||||
group={currentGroup}
|
||||
addNewRepo={this.addNewRepo}
|
||||
onGroupNameChanged={this.onGroupNameChanged}
|
||||
onGroupTransfered={this.onGroupTransfered}
|
||||
onGroupDeleted={this.onGroupDeleted}
|
||||
onLeavingGroup={this.onLeavingGroup}
|
||||
/>
|
||||
</div>
|
||||
<div className="path-tool d-flex align-items-center">
|
||||
@ -510,85 +361,6 @@ class GroupView extends React.Component {
|
||||
</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}
|
||||
/>
|
||||
}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ class Libraries extends Component {
|
||||
|
||||
const eventBus = EventBus.getInstance();
|
||||
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);
|
||||
}
|
||||
|
||||
@ -282,7 +282,7 @@ class Libraries extends Component {
|
||||
};
|
||||
*/
|
||||
|
||||
insertRepoIntoGroup = ({ repo, group_id }) => {
|
||||
addRepoToGroup = ({ repo, group_id }) => {
|
||||
if (!repo) {
|
||||
return;
|
||||
}
|
||||
@ -299,11 +299,37 @@ class Libraries extends Component {
|
||||
}
|
||||
|
||||
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.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 }) => {
|
||||
const { groupList } = this.state;
|
||||
let newGroupList = [...groupList];
|
||||
@ -498,7 +524,11 @@ class Libraries extends Component {
|
||||
onMonitorRepo={this.onMonitorRepo}
|
||||
renameRelatedGroupsRepos={this.renameRelatedGroupsRepos}
|
||||
deleteRelatedGroupsRepos={this.deleteRelatedGroupsRepos}
|
||||
insertRepoIntoGroup={this.insertRepoIntoGroup}
|
||||
addRepoToGroup={this.addRepoToGroup}
|
||||
onGroupNameChanged={this.onGroupNameChanged}
|
||||
onGroupTransfered={this.onGroupTransfered}
|
||||
onGroupDeleted={this.onGroupDeleted}
|
||||
onLeavingGroup={this.onLeavingGroup}
|
||||
unshareRepoToGroup={this.unshareRepoToGroup}
|
||||
onTransferRepo={this.onGroupTransferRepo}
|
||||
currentViewMode={currentViewMode}
|
||||
|
Loading…
Reference in New Issue
Block a user