diff --git a/frontend/src/css/system-departments-v2.css b/frontend/src/css/system-departments-v2.css
index b7992e04fe..1d767a454b 100644
--- a/frontend/src/css/system-departments-v2.css
+++ b/frontend/src/css/system-departments-v2.css
@@ -128,4 +128,6 @@
color: #21bc2e;
}
-/* 顶部的样式:背景色和边界去掉,和 seatable 保持一致 */
+.departments-members-item {
+ height: 58px;
+}
diff --git a/frontend/src/pages/sys-admin/departments-v2/departments-node-dropdown-menu.js b/frontend/src/pages/sys-admin/departments-v2/departments-node-dropdown-menu.js
new file mode 100644
index 0000000000..3606a9123b
--- /dev/null
+++ b/frontend/src/pages/sys-admin/departments-v2/departments-node-dropdown-menu.js
@@ -0,0 +1,44 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { DropdownItem, DropdownMenu } from 'reactstrap';
+import { gettext } from '../../../utils/constants';
+
+function DepartmentNodeMenu({ node, toggleDelete, toggleRename, toggleAddMembers, toggleAddDepartment, toggleAddLibrary }) {
+ return (
+
+ toggleAddDepartment(node)}>
+ {gettext('Add sub-department')}
+
+ toggleAddLibrary(node)}>
+ {gettext('Add Library')}
+
+ toggleAddMembers(node)}>
+ {gettext('Add members')}
+
+ toggleRename(node)}>
+ {gettext('Rename')}
+
+ toggleDelete(node)}>
+ {gettext('Delete')}
+
+
+ {`${gettext('Department ID')} : ${node.id}`}
+
+
+ );
+}
+
+DepartmentNodeMenu.propTypes = {
+ node: PropTypes.object.isRequired,
+ toggleDelete: PropTypes.func.isRequired,
+ toggleRename: PropTypes.func.isRequired,
+ toggleAddMembers: PropTypes.func.isRequired,
+ toggleAddDepartment: PropTypes.func.isRequired,
+ toggleAddLibrary: PropTypes.func.isRequired,
+};
+
+export default DepartmentNodeMenu;
diff --git a/frontend/src/pages/sys-admin/departments-v2/departments-v2-members-item.js b/frontend/src/pages/sys-admin/departments-v2/departments-v2-members-item.js
index 26ad635575..cdade86271 100644
--- a/frontend/src/pages/sys-admin/departments-v2/departments-v2-members-item.js
+++ b/frontend/src/pages/sys-admin/departments-v2/departments-v2-members-item.js
@@ -78,7 +78,7 @@ class DepartmentsV2MembersItem extends React.Component {
const option = options.find(item => item.value === currentRole) || {};
return (
-
 |
{member.name}
@@ -103,12 +103,12 @@ class DepartmentsV2MembersItem extends React.Component {
-
+
{gettext('Delete')}
diff --git a/frontend/src/pages/sys-admin/departments-v2/departments-v2-members-list.js b/frontend/src/pages/sys-admin/departments-v2/departments-v2-members-list.js
index 42331187ad..bfd242b66e 100644
--- a/frontend/src/pages/sys-admin/departments-v2/departments-v2-members-list.js
+++ b/frontend/src/pages/sys-admin/departments-v2/departments-v2-members-list.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { Table } from 'reactstrap';
+import { Table, Dropdown, DropdownToggle } from 'reactstrap';
import Loading from '../../../components/loading';
import EmptyTip from '../../../components/empty-tip';
import { gettext } from '../../../utils/constants';
@@ -8,6 +8,7 @@ import DepartmentsV2MembersItem from './departments-v2-members-item';
import RepoItem from '../departments/repo-item';
import ModalPortal from '../../../components/modal-portal';
import DeleteRepoDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-delete-repo-dialog';
+import DepartmentNodeMenu from './departments-node-dropdown-menu';
const propTypes = {
rootNodes: PropTypes.array,
@@ -32,6 +33,7 @@ class DepartmentsV2MembersList extends React.Component {
repos: [],
deletedRepo: {},
showDeleteRepoDialog: false,
+ dropdownOpen: false,
};
}
@@ -75,20 +77,20 @@ class DepartmentsV2MembersList extends React.Component {
this.setState({ isItemFreezed: !this.state.isItemFreezed });
};
- getDepartmentName = () => {
+ getCurrentDepartment = () => {
const { rootNodes, checkedDepartmentId } = this.props;
- if (!rootNodes) return '';
- let name = '';
+ if (!rootNodes) return {};
+ let currentDepartment = {};
let arr = [...rootNodes];
- while (!name && arr.length > 0) {
+ while (!currentDepartment.id && arr.length > 0) {
let curr = arr.shift();
if (curr.id === checkedDepartmentId) {
- name = curr.name;
+ currentDepartment = curr;
} else if (curr.children && curr.children.length > 0) {
arr.push(...curr.children);
}
}
- return name;
+ return currentDepartment;
};
sortByName = (e) => {
@@ -117,16 +119,47 @@ class DepartmentsV2MembersList extends React.Component {
});
};
+ dropdownToggle = (e) => {
+ e.stopPropagation();
+ this.setState({ dropdownOpen: !this.state.dropdownOpen });
+ };
+
render() {
const { activeNav, repos } = this.state;
const { membersList, isMembersListLoading, sortBy, sortOrder } = this.props;
const sortByName = sortBy === 'name';
const sortByRole = sortBy === 'role';
const sortIcon = ;
+ const currentDepartment = this.getCurrentDepartment();
return (
- {this.getDepartmentName()}
+
+ {currentDepartment.name}
+ this.dropdownToggle(e)}
+ direction="down"
+ className="department-dropdown-menu"
+ >
+
+
+
+
diff --git a/frontend/src/pages/sys-admin/departments-v2/departments-v2-tree-node.js b/frontend/src/pages/sys-admin/departments-v2/departments-v2-tree-node.js
index 62144758a7..efa29d16b7 100644
--- a/frontend/src/pages/sys-admin/departments-v2/departments-v2-tree-node.js
+++ b/frontend/src/pages/sys-admin/departments-v2/departments-v2-tree-node.js
@@ -1,8 +1,9 @@
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
-import { Dropdown, DropdownItem, DropdownMenu, DropdownToggle } from 'reactstrap';
+import { Dropdown, DropdownToggle } from 'reactstrap';
import { gettext } from '../../../utils/constants';
+import DepartmentNodeMenu from './departments-node-dropdown-menu';
const departmentsV2TreeNodePropTypes = {
node: PropTypes.object,
@@ -105,22 +106,6 @@ class DepartmentsV2TreeNode extends Component {
}
};
- toggleAddDepartment = (node) => {
- this.props.toggleAddDepartment(node);
- };
-
- toggleAddMembers = (node) => {
- this.props.toggleAddMembers(node);
- };
-
- toggleRename = (node) => {
- this.props.toggleRename(node);
- };
-
- toggleDelete = (node) => {
- this.props.toggleDelete(node);
- };
-
render() {
const { node, checkedDepartmentId } = this.props;
const { isChildrenShow, dropdownOpen, active } = this.state;
@@ -144,7 +129,7 @@ class DepartmentsV2TreeNode extends Component {
}
{node.name}
- {active && node.id !== 'other_users' &&
+ {active &&
this.dropdownToggle(e)}
@@ -159,55 +144,16 @@ class DepartmentsV2TreeNode extends Component {
aria-label={gettext('More operations')}
data-toggle="dropdown"
>
-
+
-
-
- {gettext('Add sub-department')}
-
-
- {gettext('Add Library')}
-
- {node.id !== -1 && (
-
-
- {gettext('Add members')}
-
-
- {gettext('Rename')}
-
-
- {gettext('Delete')}
-
-
- {`${gettext('Department ID')} : ${node.id}`}
-
-
- )}
-
+
}
diff --git a/frontend/src/pages/sys-admin/departments-v2/departments-v2.js b/frontend/src/pages/sys-admin/departments-v2/departments-v2.js
index 9355dc4b59..ea5b74a9ce 100644
--- a/frontend/src/pages/sys-admin/departments-v2/departments-v2.js
+++ b/frontend/src/pages/sys-admin/departments-v2/departments-v2.js
@@ -336,6 +336,11 @@ class DepartmentsV2 extends React.Component {
getRepos={this.getRepos}
deleteGroup={this.deleteGroup}
createGroup={this.createGroup}
+ toggleAddDepartment={this.toggleAddDepartment}
+ toggleAddLibrary={this.toggleAddLibrary}
+ toggleAddMembers={this.toggleAddMembers}
+ toggleRename={this.toggleRename}
+ toggleDelete={this.toggleDelete}
/>
>
}
diff --git a/seahub/api2/endpoints/admin/group_members.py b/seahub/api2/endpoints/admin/group_members.py
index 6753f30991..9cd0c21f8c 100644
--- a/seahub/api2/endpoints/admin/group_members.py
+++ b/seahub/api2/endpoints/admin/group_members.py
@@ -9,7 +9,7 @@ from rest_framework import status
from seaserv import seafile_api, ccnet_api
-from seahub.group.utils import get_group_member_info, is_group_member
+from seahub.group.utils import get_group_member_info, is_group_member, get_group_members_info
from seahub.group.signals import add_user_to_group
from seahub.avatar.settings import AVATAR_DEFAULT_SIZE
from seahub.base.accounts import User
@@ -67,15 +67,13 @@ class AdminGroupMembers(APIView):
else:
has_next_page = False
- group_members_info = []
- for m in members:
- member_info = get_group_member_info(request, group_id, m.user_name)
- group_members_info.append(member_info)
-
+
+ member_usernames = [m.user_name for m in members]
+ members_info = get_group_members_info(group_id, member_usernames)
group_members = {
'group_id': group_id,
'group_name': group.group_name,
- 'members': group_members_info,
+ 'members': members_info,
'page_info': {
'has_next_page': has_next_page,
'current_page': page
diff --git a/seahub/group/utils.py b/seahub/group/utils.py
index d80881098f..17ac4d0b35 100644
--- a/seahub/group/utils.py
+++ b/seahub/group/utils.py
@@ -118,6 +118,42 @@ def get_group_member_info(request, group_id, email):
return member_info
+def get_group_members_info(group_id, emails):
+ member_profiles = Profile.objects.filter(user__in=emails)
+ username_profile_map = {p.user : p for p in member_profiles}
+ members_info_list = []
+ for email in emails:
+ p = username_profile_map.get(email) or None
+ if p:
+ login_id = p.login_id if p.login_id else ''
+ contact_email = p.contact_email
+ else:
+ login_id = ''
+ contact_email = ''
+
+ avatar_url, _, _ = api_avatar_url(email)
+
+ role = 'Member'
+ group = ccnet_api.get_group(int(group_id))
+ is_admin = bool(ccnet_api.check_group_staff(int(group_id), email))
+ if email == group.creator_name:
+ role = 'Owner'
+ elif is_admin:
+ role = 'Admin'
+
+ member_info = {
+ 'group_id': group_id,
+ "name": email2nickname(email),
+ 'email': email,
+ "contact_email": contact_email,
+ "login_id": login_id,
+ "avatar_url": avatar_url,
+ "is_admin": is_admin,
+ "role": role,
+ }
+ members_info_list.append(member_info)
+ return members_info_list
+
GROUP_ID_CACHE_PREFIX = "GROUP_ID_"
GROUP_ID_CACHE_TIMEOUT = 24 * 60 * 60
|