1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-19 10:26:17 +00:00

group member pagination (#4704)

* group member pagination

* update

* update

* update

Co-authored-by: lian <lian@seafile.com>
This commit is contained in:
lian
2020-10-26 16:43:45 +08:00
committed by GitHub
parent e49ff53762
commit 2bb4074e71
5 changed files with 147 additions and 36 deletions

View File

@@ -2,6 +2,7 @@ import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import { Link } from '@reach/router';
import Paginator from '../../../components/paginator';
import { seafileAPI } from '../../../utils/seafile-api';
import { Utils } from '../../../utils/utils.js';
import toaster from '../../../components/toast';
@@ -35,6 +36,11 @@ class DepartmentDetail extends React.Component {
isItemFreezed: false,
ancestorGroups: [],
members: [],
membersErrorMsg: '',
membersPageInfo: {
},
membersPage: 1,
membersPerPage: 25,
deletedMember: {},
isShowAddMemberDialog: false,
showDeleteMemberDialog: false,
@@ -54,13 +60,15 @@ class DepartmentDetail extends React.Component {
componentDidMount() {
const groupID = this.props.groupID;
this.listGroupRepo(groupID);
this.listMembers(groupID);
this.getDepartmentInfo(groupID);
this.listMembers(groupID, this.state.membersPage, this.state.membersPerPage);
}
componentWillReceiveProps(nextProps) {
if (this.props.groupID !== nextProps.groupID) {
this.listGroupRepo(nextProps.groupID);
this.listMembers(nextProps.groupID);
this.getDepartmentInfo(nextProps.groupID);
this.listMembers(nextProps.groupID, this.state.membersPage, this.state.membersPerPage);
}
}
@@ -73,10 +81,9 @@ class DepartmentDetail extends React.Component {
});
}
listMembers = (groupID) => {
getDepartmentInfo = (groupID) => {
seafileAPI.sysAdminGetDepartmentInfo(groupID, true).then(res => {
this.setState({
members: res.data.members,
groups: res.data.groups,
ancestorGroups: res.data.ancestor_groups,
groupName: res.data.name,
@@ -87,6 +94,34 @@ class DepartmentDetail extends React.Component {
});
}
listMembers = (groupID, page, perPage) => {
seafileAPI.sysAdminListGroupMembers(groupID, page, perPage).then((res) => {
this.setState({
members: res.data.members,
membersPageInfo: res.data.page_info
});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
this.setState({membersErrorMsg: errMessage});
});
}
getPreviousPageList = () => {
this.listMembers(this.props.groupID, this.state.membersPageInfo.current_page - 1, this.state.membersPerPage);
}
getNextPageList = () => {
this.listMembers(this.props.groupID, this.state.membersPageInfo.current_page + 1, this.state.membersPerPage);
}
resetPerPage = (perPage) => {
this.setState({
membersPerPage: perPage
}, () => {
this.listMembers(this.props.groupID, 1, perPage);
});
}
listSubDepartGroups = (groupID) => {
seafileAPI.sysAdminGetDepartmentInfo(groupID, true).then(res => {
this.setState({ groups: res.data.groups });
@@ -114,7 +149,7 @@ class DepartmentDetail extends React.Component {
}
onMemberChanged = () => {
this.listMembers(this.props.groupID);
this.listMembers(this.props.groupID, this.state.membersPageInfo.current_page, this.state.membersPerPage);
}
toggleItemFreezed = (isFreezed) => {
@@ -142,7 +177,7 @@ class DepartmentDetail extends React.Component {
}
showDeleteDepartDialog = (subGroup) => {
this.setState({
this.setState({
showDeleteDepartDialog: true,
subGroupID: subGroup.id,
subGroupName: subGroup.name
@@ -157,7 +192,7 @@ class DepartmentDetail extends React.Component {
}
render() {
const { members, repos, groups } = this.state;
const { members, membersErrorMsg, repos, groups } = this.state;
const groupID = this.props.groupID;
const topBtn = 'btn btn-secondary operation-item';
const topbarChildren = (
@@ -207,7 +242,7 @@ class DepartmentDetail extends React.Component {
<div className="cur-view-path">
<div className="fleft">
<h3 className="sf-heading">
{groupID ?
{groupID ?
<Link to={siteRoot + 'sys/departments/'}>{gettext('Departments')}</Link>
: <span>{gettext('Departments')}</span>
}
@@ -253,14 +288,16 @@ class DepartmentDetail extends React.Component {
}
</div>
</div>
<div className="cur-view-subcontainer org-members">
<div className="cur-view-path">
<div className="fleft"><h3 className="sf-heading">{gettext('Members')}</h3></div>
</div>
<div className="cur-view-content">
{(members && members.length === 1 && members[0].role === 'Owner') ?
{membersErrorMsg ? <p className="error text-center">{membersErrorMsg}</p> :
members.length == 0 ?
<p className="no-member">{gettext('No members')}</p> :
<Fragment>
<table>
<thead>
<tr>
@@ -287,6 +324,17 @@ class DepartmentDetail extends React.Component {
})}
</tbody>
</table>
{this.state.membersPageInfo &&
<Paginator
gotoPreviousPage={this.getPreviousPageList}
gotoNextPage={this.getNextPageList}
currentPage={this.state.membersPageInfo.current_page}
hasNextPage={this.state.membersPageInfo.has_next_page}
curPerPage={this.state.membersPerPage}
resetPerPage={this.resetPerPage}
/>
}
</Fragment>
}
</div>
</div>

View File

@@ -6,6 +6,7 @@ import { siteRoot, gettext } from '../../../utils/constants';
import toaster from '../../../components/toast';
import EmptyTip from '../../../components/empty-tip';
import Loading from '../../../components/loading';
import Paginator from '../../../components/paginator';
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
import SysAdminGroupAddMemberDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-group-add-member-dialog';
import SysAdminGroupRoleEditor from '../../../components/select-editor/sysadmin-group-role-editor';
@@ -19,8 +20,16 @@ class Content extends Component {
super(props);
}
getPreviousPageList = () => {
this.props.getListByPage(this.props.pageInfo.current_page - 1);
}
getNextPageList = () => {
this.props.getListByPage(this.props.pageInfo.current_page + 1);
}
render() {
const { loading, errorMsg, items } = this.props;
const { loading, errorMsg, items, pageInfo, curPerPage } = this.props;
if (loading) {
return <Loading />;
} else if (errorMsg) {
@@ -53,9 +62,19 @@ class Content extends Component {
})}
</tbody>
</table>
{pageInfo &&
<Paginator
gotoPreviousPage={this.getPreviousPageList}
gotoNextPage={this.getNextPageList}
currentPage={pageInfo.current_page}
hasNextPage={pageInfo.has_next_page}
curPerPage={curPerPage}
resetPerPage={this.props.resetPerPage}
/>
}
</Fragment>
);
return items.length ? table : emptyTip;
return items.length ? table : emptyTip;
}
}
}
@@ -110,7 +129,7 @@ class Item extends Component {
<td>
{item.role == 'Owner' ?
gettext('Owner') :
<SysAdminGroupRoleEditor
<SysAdminGroupRoleEditor
isTextMode={true}
isEditIconShow={isOpIconShown}
roleOptions={['Member', 'Admin']}
@@ -126,7 +145,7 @@ class Item extends Component {
</td>
</tr>
{isDeleteDialogOpen &&
<CommonOperationConfirmationDialog
<CommonOperationConfirmationDialog
title={gettext('Remove Member')}
message={dialogMsg}
executeOperation={this.removeMember}
@@ -148,16 +167,33 @@ class GroupMembers extends Component {
errorMsg: '',
groupName: '',
memberList: [],
pageInfo: {},
currentPage: 1,
perPage: 25,
isAddMemberDialogOpen: false
};
}
componentDidMount () {
seafileAPI.sysAdminListGroupMembers(this.props.groupID).then((res) => {
let urlParams = (new URL(window.location)).searchParams;
const { currentPage, perPage } = this.state;
this.setState({
currentPage: parseInt(urlParams.get('page') || currentPage),
perPage: parseInt(urlParams.get('per_page') || perPage)
}, () => {
this.getListByPage(this.state.currentPage);
});
}
getListByPage = (page) => {
const { perPage } = this.state;
seafileAPI.sysAdminListGroupMembers(this.props.groupID, page, perPage).then((res) => {
this.setState({
loading: false,
memberList: res.data.members,
groupName: res.data.group_name
groupName: res.data.group_name,
pageInfo: res.data.page_info
});
}).catch((error) => {
this.setState({
@@ -167,6 +203,14 @@ class GroupMembers extends Component {
});
}
resetPerPage = (perPage) => {
this.setState({
perPage: perPage
}, () => {
this.getListByPage(1);
});
}
toggleAddMemgerDialog = () => {
this.setState({isAddMemberDialogOpen: !this.state.isAddMemberDialogOpen});
}
@@ -238,7 +282,7 @@ class GroupMembers extends Component {
</MainPanelTopbar>
<div className="main-panel-center flex-row">
<div className="cur-view-container">
<GroupNav
<GroupNav
currentItem="members"
groupID={this.props.groupID}
groupName={this.state.groupName}
@@ -250,6 +294,10 @@ class GroupMembers extends Component {
items={this.state.memberList}
removeMember={this.removeMember}
updateMemberRole={this.updateMemberRole}
pageInfo={this.state.pageInfo}
curPerPage={this.state.perPage}
getListByPage={this.getListByPage}
resetPerPage={this.resetPerPage}
/>
</div>
</div>

View File

@@ -184,20 +184,7 @@ class AdminAddressBookGroup(APIView):
for group in groups:
ret_groups.append(address_book_group_to_dict(group))
try:
members = ccnet_api.get_group_members(group_id)
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
for m in members:
member_info = self._get_address_book_group_memeber_info(request,
m, avatar_size)
ret_members.append(member_info)
ret_dict['groups'] = ret_groups
ret_dict['members'] = ret_members
if return_ancestors:
# get ancestor groups and remove last group which is self

View File

@@ -45,18 +45,33 @@ class AdminGroupMembers(APIView):
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
try:
avatar_size = int(request.GET.get('avatar_size',
AVATAR_DEFAULT_SIZE))
avatar_size = int(request.GET.get('avatar_size', AVATAR_DEFAULT_SIZE))
except ValueError:
avatar_size = AVATAR_DEFAULT_SIZE
try:
members = ccnet_api.get_group_members(group_id)
page = int(request.GET.get('page', '1'))
per_page = int(request.GET.get('per_page', '100'))
except ValueError:
page = 1
per_page = 100
start = (page - 1) * per_page
limit = per_page + 1
try:
members = ccnet_api.get_group_members(group_id, start, limit)
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
if len(members) > per_page:
members = members[:per_page]
has_next_page = True
else:
has_next_page = False
group_members_info = []
for m in members:
member_info = get_group_member_info(request, group_id, m.user_name, avatar_size)
@@ -65,9 +80,12 @@ class AdminGroupMembers(APIView):
group_members = {
'group_id': group_id,
'group_name': group.group_name,
'members': group_members_info
'members': group_members_info,
'page_info': {
'has_next_page': has_next_page,
'current_page': page
}
}
return Response(group_members)
def post(self, request, group_id):

View File

@@ -45,13 +45,23 @@ class GroupMembers(APIView):
except ValueError:
avatar_size = AVATAR_DEFAULT_SIZE
try:
page = int(request.GET.get('page', '1'))
per_page = int(request.GET.get('per_page', '100'))
except ValueError:
page = 1
per_page = 100
start = (page - 1) * per_page
limit = per_page
try:
# only group member can get info of all group members
if not is_group_member(group_id, request.user.username):
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
members = ccnet_api.get_group_members(group_id)
members = ccnet_api.get_group_members(group_id, start, limit)
except SearpcError as e:
logger.error(e)