1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-03 07:55:36 +00:00

Share to user support select department (#7327)

* select department user when share repo to user

* update

* update

* 01 fix code warnings

* 02 change dialog style

* 03 manage group members support select department user

---------

Co-authored-by: Michael An <2331806369@qq.com>
This commit is contained in:
lian
2025-01-13 18:18:58 +08:00
committed by GitHub
parent dd3003a693
commit 20c81de6cf
17 changed files with 1241 additions and 19 deletions

View File

@@ -0,0 +1,249 @@
import React, { Fragment, } from 'react';
import PropTypes from 'prop-types';
import { gettext, isOrgContext, username } from '../../utils/constants';
import { Modal, ModalBody } from 'reactstrap';
import { seafileAPI } from '../../utils/seafile-api.js';
import { Utils } from '../../utils/utils';
import toaster from '../../components/toast';
import EmptyTip from '../../components/empty-tip';
import Loading from '../../components/loading';
import Department from '../../models/department';
import SeahubModalHeader from '../common/seahub-modal-header';
import DepartmentGroup from './department-detail-widget/department-group';
import DepartmentGroupMembers from './department-detail-widget/department-group-members';
import DepartmentGroupMemberSelected from './department-detail-widget/department-group-member-selected';
import '../../css/manage-members-dialog.css';
import '../../css/group-departments.css';
const propTypes = {
groupID: PropTypes.any,
toggleManageMembersDialog: PropTypes.func,
toggleDepartmentDetailDialog: PropTypes.func,
isOwner: PropTypes.bool,
addUserShares: PropTypes.func,
usedFor: PropTypes.oneOf(['add_group_member', 'add_user_share']),
userList: PropTypes.array,
};
class DepartmentDetailDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
departments: [],
departmentMembers: [],
newMembersTempObj: {},
currentDepartment: {},
departmentsLoading: true,
membersLoading: true,
selectedMemberMap: {},
departmentsTree: [],
};
}
componentDidMount() {
this.getSelectedMembers();
this.getDepartmentsList();
}
getSelectedMembers = () => {
const { usedFor, userList, groupID } = this.props;
if (usedFor === 'add_user_share') {
let selectedMemberMap = {};
selectedMemberMap[username] = true;
userList.forEach(member => {
selectedMemberMap[member.email] = true;
});
this.setState({ selectedMemberMap });
}
else if (usedFor === 'add_group_member') {
seafileAPI.listGroupMembers(groupID).then((res) => {
const groupMembers = res.data;
let selectedMemberMap = {};
selectedMemberMap[username] = true;
groupMembers.forEach(member => {
selectedMemberMap[member.email] = true;
});
this.setState({ selectedMemberMap });
}).catch(error => {
this.onError(error);
});
}
};
onError = (error) => {
let errMsg = Utils.getErrorMsg(error, true);
if (!error.response || error.response.status !== 403) {
toaster.danger(errMsg);
}
};
initDepartments(departments) {
const parentIdMap = {};
for (let i = 0; i < departments.length; i++) {
let item = departments[i];
parentIdMap[item.parent_group_id] = true;
}
return departments.map(depart => {
depart.hasChild = !!parentIdMap[depart.id];
depart.isExpanded = false;
return depart;
});
}
getDepartmentsList = () => {
seafileAPI.listAddressBookDepartments().then((res) => {
let departments = res.data.departments.map(item => {
return new Department(item);
});
let currentDepartment = departments.length > 0 ? departments[0] : {};
let departmentsTree = this.initDepartments(departments);
this.setState({
departments: departments,
currentDepartment: currentDepartment,
departmentsLoading: false,
departmentsTree: departmentsTree
});
this.getMembers(currentDepartment.id);
}).catch(error => {
this.onError(error);
});
};
getMembers = (department_id) => {
this.setState({ membersLoading: true });
seafileAPI.listAddressBookDepartmentMembers(department_id).then((res) => {
this.setState({
departmentMembers: res.data.members,
membersLoading: false,
});
}).catch(error => {
this.onError(error);
});
};
toggle = () => {
this.props.toggleDepartmentDetailDialog();
};
onMemberChecked = (member) => {
if (this.state.departmentMembers.indexOf(member) !== -1) {
let newMembersTempObj = this.state.newMembersTempObj;
if (member.email in newMembersTempObj) {
delete newMembersTempObj[member.email];
} else {
newMembersTempObj[member.email] = member;
}
this.setState({ newMembersTempObj: newMembersTempObj });
}
};
addGroupMember = () => {
let emails = Object.keys(this.state.newMembersTempObj);
seafileAPI.addGroupMembers(this.props.groupID, emails).then((res) => {
this.toggle();
this.props.toggleManageMembersDialog();
}).catch(error => {
this.onError(error);
});
};
addUserShares = () => {
this.props.addUserShares(this.state.newMembersTempObj);
};
removeSelectedMember = (email) => {
let newMembersTempObj = this.state.newMembersTempObj;
delete newMembersTempObj[email];
this.setState({ newMembersTempObj: newMembersTempObj });
};
setCurrent = (department) => {
this.setState({ currentDepartment: department });
};
selectAll = (members) => {
let { newMembersTempObj, selectedMemberMap } = this.state;
for (let member of members) {
if (Object.keys(selectedMemberMap).indexOf(member.email) !== -1) {
continue;
}
newMembersTempObj[member.email] = member;
}
this.setState({ newMembersTempObj: newMembersTempObj });
};
renderHeader = () => {
const title = this.props.usedFor === 'add_group_member' ? gettext('Select group members') : gettext('Select shared users');
return <SeahubModalHeader toggle={this.toggle}>{title}</SeahubModalHeader>;
};
render() {
let { departmentsLoading, departments } = this.state;
if (departmentsLoading) {
return (
<Modal isOpen={true} toggle={this.toggle}>
{this.renderHeader()}
<ModalBody>
<div className="d-flex flex-fill align-items-center"><Loading /></div>
</ModalBody>
</Modal>
);
}
const emptyTips = (
<Modal isOpen={true} toggle={this.toggle}>
{this.renderHeader()}
<ModalBody>
<EmptyTip>
<h2>{gettext('No departments')}</h2>
</EmptyTip>
</ModalBody>
</Modal>
);
const details = (
<Modal isOpen={true} toggle={this.toggle} className="department-dialog" style={{ maxWidth: '900px' }}>
{this.renderHeader()}
<ModalBody className="department-dialog-content">
<DepartmentGroup
departments={this.state.departments}
getMembers={this.getMembers}
setCurrent={this.setCurrent}
currentDepartment={this.state.currentDepartment}
loading={this.state.departmentsLoading}
departmentsTree={this.state.departmentsTree}
/>
<DepartmentGroupMembers
members={this.state.departmentMembers}
memberSelected={this.state.newMembersTempObj}
onUserChecked={this.onMemberChecked}
currentDepartment={this.state.currentDepartment}
selectAll={this.selectAll}
loading={this.state.membersLoading}
selectedMemberMap={this.state.selectedMemberMap}
isLoadingMore={this.state.isLoadingMore}
usedFor={this.props.usedFor}
/>
<DepartmentGroupMemberSelected
members={this.state.newMembersTempObj}
removeSelectedMember={this.removeSelectedMember}
addGroupMember={this.addGroupMember}
toggle={this.toggle}
addUserShares={this.addUserShares}
usedFor={this.props.usedFor}
/>
</ModalBody>
</Modal>
);
return (
<Fragment>
{(departments.length > 0 || isOrgContext) ? details : emptyTips}
</Fragment>
);
}
}
DepartmentDetailDialog.propTypes = propTypes;
export default DepartmentDetailDialog;

View File

@@ -0,0 +1,107 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Button, ModalFooter } from 'reactstrap';
import { gettext } from '../../../utils/constants';
const ItemPropTypes = {
member: PropTypes.object,
removeSelectedMember: PropTypes.func
};
class Item extends Component {
constructor(props) {
super(props);
this.state = {
highlight: false,
};
}
handleMouseEnter = () => {
this.setState({ highlight: true });
};
handleMouseLeave = () => {
this.setState({ highlight: false });
};
removeSelectedMember = (email) => {
this.props.removeSelectedMember(email);
};
render() {
const { member } = this.props;
return (
<tr
className={this.state.highlight ? 'tr-highlight group-item' : 'group-item'}
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
>
<td width="17%"><img className="avatar" src={member.avatar_url} alt=""/></td>
<td width="78%">{member.name}</td>
<td width="10%">
<i
className="sf3-font sf3-font-close cursor-pointer"
name={member.email}
onClick={this.removeSelectedMember.bind(this, member.email)}>
</i>
</td>
</tr>
);
}
}
Item.propTypes = ItemPropTypes;
const DepartmentGroupMemberSelectedPropTypes = {
members: PropTypes.object.isRequired,
removeSelectedMember: PropTypes.func.isRequired,
addGroupMember: PropTypes.func.isRequired,
toggle: PropTypes.func.isRequired,
usedFor: PropTypes.string,
addUserShares: PropTypes.func,
};
class DepartmentGroupMemberSelected extends Component {
render() {
const { members, usedFor } = this.props;
return (
<div className="department-dialog-member-selected pt-4">
<div style={{ height: 'calc(100% - 70px)' }}>
<div className='department-dialog-member-head px-4'>
<div className='department-name'>{gettext('Selected')}</div>
</div>
{Object.keys(members).length > 0 &&
<table className="department-dialog-member-table">
<tbody>
{Object.keys(members).map((email, index) => {
return (
<Item
key={index}
member={members[email]}
removeSelectedMember={this.props.removeSelectedMember}
/>
);
})}
</tbody>
</table>
}
</div>
<ModalFooter>
<Button color="secondary" onClick={this.props.toggle}>{gettext('Cancel')}</Button>
{usedFor === 'add_group_member' &&
<Button color="primary" onClick={this.props.addGroupMember}>{gettext('Add')}</Button>
}
{usedFor === 'add_user_share' &&
<Button color="primary" onClick={this.props.addUserShares}>{gettext('Add')}</Button>
}
</ModalFooter>
</div>
);
}
}
DepartmentGroupMemberSelected.propTypes = DepartmentGroupMemberSelectedPropTypes;
export default DepartmentGroupMemberSelected;

View File

@@ -0,0 +1,175 @@
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { Tooltip } from 'reactstrap';
import { gettext, mediaUrl } from '../../../utils/constants';
import EmptyTip from '../../../components/empty-tip';
import Loading from '../../../components/loading';
const ItemPropTypes = {
member: PropTypes.object,
index: PropTypes.number,
tip: PropTypes.string,
memberSelected: PropTypes.object,
isMemberSelected: PropTypes.bool,
onUserChecked: PropTypes.func.isRequired,
};
class Item extends Component {
constructor(props) {
super(props);
this.state = {
highlight: false,
tooltipOpen: false,
};
}
handleMouseEnter = () => {
this.setState({ highlight: true });
};
handleMouseLeave = () => {
this.setState({ highlight: false });
};
onChange = (e) => {
const { member } = this.props;
this.props.onUserChecked(member);
};
toggleTooltip = () => {
this.setState({ tooltipOpen: !this.state.tooltipOpen });
};
render() {
const { member, memberSelected, isMemberSelected, index, tip } = this.props;
if (isMemberSelected) {
return (
<tr
className={this.state.highlight ? 'tr-highlight group-item' : 'group-item'}
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
>
<td width="13%">
<input type="checkbox" className="vam" checked='checked' disabled/>
</td>
<td width="11%"><img className="avatar" src={member.avatar_url} alt=""/></td>
<td width="60%">{member.name}</td>
<td width="16%" className={this.state.highlight ? 'visible' : 'invisible' }>
<i className="sf3-font-help sf3-font" id={`no-select-${index}`}></i>
<Tooltip placement='bottom' isOpen={this.state.tooltipOpen} toggle={this.toggleTooltip} target={`no-select-${index}`} delay={{ show: 0, hide: 0 }} fade={false}>
{tip}
</Tooltip>
</td>
</tr>
);
}
return (
<tr
className={this.state.highlight ? 'tr-highlight group-item' : 'group-item'}
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
>
<td width="13%">
<input
type="checkbox"
className="vam"
onChange={this.onChange}
checked={(member.email in memberSelected) ? 'checked' : ''}
/>
</td>
<td width="11%"><img className="avatar" src={member.avatar_url} alt=""/></td>
<td width="76%">{member.name}</td>
</tr>
);
}
}
Item.propTypes = ItemPropTypes;
const DepartmentGroupMembersPropTypes = {
members: PropTypes.array.isRequired,
memberSelected: PropTypes.object.isRequired,
onUserChecked: PropTypes.func.isRequired,
currentDepartment: PropTypes.object.isRequired,
selectedMemberMap: PropTypes.object,
selectAll: PropTypes.func.isRequired,
loading: PropTypes.bool,
usedFor: PropTypes.oneOf(['add_group_member', 'add_user_share']),
};
class DepartmentGroupMembers extends Component {
selectAll = () => {
const { members } = this.props;
this.props.selectAll(members);
};
render() {
const { members, memberSelected, loading, selectedMemberMap, currentDepartment, usedFor } = this.props;
let headerTitle;
if (currentDepartment.id === -1) {
headerTitle = gettext('All users');
} else {
headerTitle = currentDepartment.name + ' ' + gettext('members');
}
if (loading) {
return (
<div className="department-dialog-member pt-4">
<div className="w-100">
<div className='department-dialog-member-head px-4 mt-4'>
<Loading />
</div>
</div>
</div>
);
}
const enableSelectAll = Object.keys(memberSelected).length < members.length;
const tip = usedFor === 'add_group_member' ? gettext('User is already in this group') : gettext('It is already shared to user');
return (
<div className="department-dialog-member pt-4">
<div className="w-100">
<div className='department-dialog-member-head px-4'>
<div className='department-name'>
{headerTitle}
</div>
{enableSelectAll ?
<div className='select-all' onClick={this.selectAll}>{gettext('Select All')}</div>
:
<div className='select-all-disable'>{gettext('Select All')}</div>
}
</div>
{members.length > 0 ?
<Fragment>
<table className="department-dialog-member-table">
<tbody>
{members.map((member, index) => {
return (
<Item
key={index}
index={index}
member={member}
tip={tip}
memberSelected={memberSelected}
onUserChecked={this.props.onUserChecked}
isMemberSelected={selectedMemberMap[member.email]}
/>
);
})}
</tbody>
</table>
</Fragment>
:
<EmptyTip tipSrc={`${mediaUrl}img/no-users-tip.png`}>
<h2>{gettext('No members')}</h2>
</EmptyTip>
}
</div>
</div>
);
}
}
DepartmentGroupMembers.propTypes = DepartmentGroupMembersPropTypes;
export default DepartmentGroupMembers;

View File

@@ -0,0 +1,151 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Loading from '../../../components/loading';
import { gettext, isOrgContext } from '../../../utils/constants';
const ItemPropTypes = {
department: PropTypes.object,
departments: PropTypes.array,
getMembers: PropTypes.func.isRequired,
setCurrent: PropTypes.func.isRequired,
toggleExpanded: PropTypes.func.isRequired,
currentDepartment: PropTypes.object,
allMembersClick: PropTypes.bool,
};
class Item extends Component {
getMembers = (e) => {
e.stopPropagation();
const { department } = this.props;
this.props.getMembers(department.id);
this.props.setCurrent(department);
};
toggleExpanded = (e) => {
e.stopPropagation();
this.props.toggleExpanded(this.props.department.id, !this.props.department.isExpanded);
};
renderSubDepartments = () => {
const { departments } = this.props;
return (
<div style={{ paddingLeft: '10px' }}>
{departments.map((department, index) => {
if (department.parent_group_id !== this.props.department.id) return null;
return (
<Item
key={department.id}
department={department}
departments={departments}
getMembers={this.props.getMembers}
setCurrent={this.props.setCurrent}
toggleExpanded={this.props.toggleExpanded}
currentDepartment={this.props.currentDepartment}
allMembersClick={this.props.allMembersClick}
/>
);
})}
</div>
);
};
render() {
const { department, currentDepartment, allMembersClick } = this.props;
const isCurrent = !allMembersClick && currentDepartment.id === department.id;
const { hasChild, isExpanded } = department;
return (
<>
<div className={isCurrent ? 'tr-highlight group-item' : 'group-item'} onClick={this.getMembers}>
{hasChild &&
<span
className={`sf3-font sf3-font-down ${isExpanded ? '' : 'rotate-270'} d-inline-block`}
onClick={this.toggleExpanded}
style={{ color: isCurrent ? '#fff' : '#999', fontSize: '12px' }}
>
</span>
}
<span style={hasChild ? { paddingLeft: '8px' } : { paddingLeft: '20px' }}>{department.name}</span>
</div>
{(isExpanded && hasChild) && this.renderSubDepartments()}
</>
);
}
}
Item.propTypes = ItemPropTypes;
const DepartmentGroupPropTypes = {
departments: PropTypes.array.isRequired,
getMembers: PropTypes.func.isRequired,
setCurrent: PropTypes.func.isRequired,
currentDepartment: PropTypes.object.isRequired,
loading: PropTypes.bool,
departmentsTree: PropTypes.array,
};
class DepartmentGroup extends Component {
constructor(props) {
super(props);
this.state = {
allMembersClick: !!isOrgContext
};
}
toggleExpanded = (id, state) => {
let departments = this.props.departmentsTree.slice(0);
let index = departments.findIndex(item => item.id === id);
departments[index].isExpanded = state;
this.setState({ departments });
};
getMembers = (department_id) => {
this.props.getMembers(department_id);
this.setState({ allMembersClick: false });
};
render() {
const { loading } = this.props;
let departments = this.props.departmentsTree;
if (loading) {
return (<Loading/>);
}
const { allMembersClick } = this.state;
return (
<div className="department-dialog-group">
<div>
{isOrgContext &&
<div className={allMembersClick ? 'tr-highlight group-item' : 'group-item'}>
<span
className={'pr-2'}
style={{ color: allMembersClick ? '#fff' : '#999', fontSize: '12px' }}
/>
<span>{gettext('All users')}</span>
</div>
}
{departments.length > 0 && departments.map((department, index) => {
if (department.parent_group_id !== -1) return null;
return (
<Item
key={department.id}
department={department}
departments={departments}
getMembers={this.getMembers}
setCurrent={this.props.setCurrent}
toggleExpanded={this.toggleExpanded}
currentDepartment={this.props.currentDepartment}
allMembersClick={this.state.allMembersClick}
/>
);
})}
</div>
</div>
);
}
}
DepartmentGroup.propTypes = DepartmentGroupPropTypes;
export default DepartmentGroup;

View File

@@ -10,20 +10,23 @@ import '../../css/manage-members-dialog.css';
const propTypes = {
groupID: PropTypes.string,
isOwner: PropTypes.bool.isRequired,
toggleManageMembersDialog: PropTypes.func.isRequired
toggleManageMembersDialog: PropTypes.func,
toggleDepartmentDetailDialog: PropTypes.func,
};
class ManageMembersDialog extends React.Component {
render() {
const { groupID, isOwner, toggleManageMembersDialog: toggle } = this.props;
const { groupID, isOwner } = this.props;
return (
<Modal isOpen={true} toggle={toggle} className="group-manage-members-dialog">
<SeahubModalHeader toggle={toggle}>{gettext('Manage group members')}</SeahubModalHeader>
<Modal isOpen={true} toggle={this.props.toggleManageMembersDialog} className="group-manage-members-dialog">
<SeahubModalHeader toggle={this.props.toggleManageMembersDialog}>{gettext('Manage group members')}</SeahubModalHeader>
<ModalBody className="pb-0">
<ListAndAddGroupMembers
groupID={groupID}
isOwner={isOwner}
toggleManageMembersDialog={this.props.toggleManageMembersDialog}
toggleDepartmentDetailDialog={this.props.toggleDepartmentDetailDialog}
/>
</ModalBody>
</Modal>

View File

@@ -1,12 +1,14 @@
import React, { Fragment } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { gettext, isPro, cloudMode, isOrgContext } from '../../utils/constants';
import { Button } from 'reactstrap';
import { gettext, isPro } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import toaster from '../toast';
import UserSelect from '../user-select';
import SharePermissionEditor from '../select-editor/share-permission-editor';
import DepartmentDetailDialog from './department-detail-dialog';
import '../../css/invitations.css';
import '../../css/share-to-user.css';
@@ -167,7 +169,9 @@ class ShareToUser extends React.Component {
errorMsg: [],
permission: 'rw',
sharedItems: [],
isWiki: this.props.repoType === 'wiki'
isWiki: this.props.repoType === 'wiki',
tmpUserList: [],
isShowDepartmentDetailDialog: false
};
this.options = [];
this.permissions = [];
@@ -198,7 +202,16 @@ class ShareToUser extends React.Component {
let repoID = this.props.repoID;
seafileAPI.listSharedItems(repoID, path, 'user').then((res) => {
if (res.data.length !== 0) {
this.setState({ sharedItems: res.data });
let tmpUserList = res.data.map(item => {
return {
'email': item.user_info.name,
'name': item.user_info.nickname,
'avatar_url': item.user_info.avatar_url,
'contact_email': item.user_info.contact_email,
'permission': item.permission
};
});
this.setState({ sharedItems: res.data, tmpUserList: tmpUserList });
}
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
@@ -341,7 +354,88 @@ class ShareToUser extends React.Component {
this.setState({ sharedItems: sharedItems });
};
toggleDepartmentDetailDialog = () => {
this.setState({ isShowDepartmentDetailDialog: !this.state.isShowDepartmentDetailDialog });
};
addUserShares = (membersSelectedObj) => {
let path = this.props.itemPath;
let repoID = this.props.repoID;
let users = Object.keys(membersSelectedObj);
if (this.props.isGroupOwnedRepo) {
seafileAPI.shareGroupOwnedRepoToUser(repoID, this.state.permission, users, path).then(res => {
let errorMsg = [];
if (res.data.failed.length > 0) {
for (let i = 0 ; i < res.data.failed.length ; i++) {
errorMsg[i] = res.data.failed[i];
}
}
// todo modify api
let items = res.data.success.map(item => {
let sharedItem = {
'user_info': { 'nickname': item.user_name, 'name': item.user_email },
'permission': item.permission,
'share_type': 'user',
};
return sharedItem;
});
this.setState({
errorMsg: errorMsg,
sharedItems: this.state.sharedItems.concat(items),
selectedOption: null,
permission: 'rw',
});
this.refs.userSelect.clearSelect();
}).catch(error => {
if (error.response) {
let message = gettext('Library can not be shared to owner.');
let errMessage = [];
errMessage.push(message);
this.setState({
errorMsg: errMessage,
selectedOption: null,
});
}
});
} else {
seafileAPI.shareFolder(repoID, path, 'user', this.state.permission, users).then(res => {
let errorMsg = [];
if (res.data.failed.length > 0) {
for (let i = 0 ; i < res.data.failed.length ; i++) {
errorMsg[i] = res.data.failed[i];
}
}
this.setState({
errorMsg: errorMsg,
sharedItems: this.state.sharedItems.concat(res.data.success),
selectedOption: null,
permission: 'rw',
});
this.refs.userSelect.clearSelect();
}).catch(error => {
if (error.response) {
let message = gettext('Library can not be shared to owner.');
let errMessage = [];
errMessage.push(message);
this.setState({
errorMsg: errMessage,
selectedOption: null,
});
}
});
}
this.toggleDepartmentDetailDialog();
};
render() {
let showDeptBtn = true;
if (window.app.config.lang !== 'zh-cn') {
showDeptBtn = false;
}
if (cloudMode && !isOrgContext) {
showDeptBtn = false;
}
let { sharedItems } = this.state;
const thead = (
<thead>
@@ -353,18 +447,28 @@ class ShareToUser extends React.Component {
</thead>
);
return (
<Fragment>
<div className="share-link-container">
<table className="w-xs-200">
{thead}
<tbody>
<tr>
<td>
<UserSelect
ref="userSelect"
isMulti={true}
placeholder={gettext('Search users')}
onSelectChange={this.handleSelectChange}
/>
<div className='add-members'>
<UserSelect
ref="userSelect"
isMulti={true}
className={classnames('reviewer-select', { 'user-select-right-btn': showDeptBtn })}
placeholder={gettext('Search users...')}
onSelectChange={this.handleSelectChange}
excludeCurrentUser={false}
/>
{showDeptBtn &&
<span
onClick={this.toggleDepartmentDetailDialog}
className="sf3-font sf3-font-invite-visitors toggle-detail-btn">
</span>
}
</div>
</td>
<td>
<SharePermissionEditor
@@ -411,8 +515,16 @@ class ShareToUser extends React.Component {
onChangeUserPermission={this.onChangeUserPermission}
/>
</table>
{this.state.isShowDepartmentDetailDialog &&
<DepartmentDetailDialog
toggleDepartmentDetailDialog={this.toggleDepartmentDetailDialog}
addUserShares={this.addUserShares}
userList={this.state.tmpUserList}
usedFor='add_user_share'
/>
}
</div>
</Fragment>
</div>
);
}
}

View File

@@ -2,7 +2,7 @@ import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { Button, InputGroup, InputGroupText, Input } from 'reactstrap';
import { Utils } from '../utils/utils';
import { gettext } from '../utils/constants';
import { gettext, cloudMode, isOrgContext } from '../utils/constants';
import { seafileAPI } from '../utils/seafile-api';
import UserSelect from './user-select';
import toaster from './toast';
@@ -10,6 +10,8 @@ import Loading from './loading';
import GroupMembers from './group-members';
const propTypes = {
toggleManageMembersDialog: PropTypes.func,
toggleDepartmentDetailDialog: PropTypes.func,
groupID: PropTypes.string,
isOwner: PropTypes.bool.isRequired
};
@@ -159,12 +161,24 @@ class ManageMembersDialog extends React.Component {
});
};
onClickDeptBtn = () => {
this.props.toggleManageMembersDialog();
this.props.toggleDepartmentDetailDialog();
};
render() {
const {
isLoading, hasNextPage, groupMembers,
keyword, membersFound,
searchActive
} = this.state;
let showDeptBtn = true;
if (window.app.config.lang !== 'zh-cn') {
showDeptBtn = false;
}
if (cloudMode && !isOrgContext) {
showDeptBtn = false;
}
return (
<Fragment>
<p className="mb-2">{gettext('Add group member')}</p>
@@ -176,6 +190,9 @@ class ManageMembersDialog extends React.Component {
isMulti={true}
className="add-members-select"
/>
{showDeptBtn &&
<span onClick={this.onClickDeptBtn} className="sf3-font sf3-font-invite-visitors toggle-detail-btn"></span>
}
{this.state.selectedOption ?
<Button color="primary" onClick={this.addGroupMember}>{gettext('Submit')}</Button> :
<Button color="primary" disabled>{gettext('Submit')}</Button>