1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-20 10:58:33 +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 PropTypes from 'prop-types';
import moment from 'moment'; import moment from 'moment';
import { Link } from '@reach/router'; import { Link } from '@reach/router';
import Paginator from '../../../components/paginator';
import { seafileAPI } from '../../../utils/seafile-api'; import { seafileAPI } from '../../../utils/seafile-api';
import { Utils } from '../../../utils/utils.js'; import { Utils } from '../../../utils/utils.js';
import toaster from '../../../components/toast'; import toaster from '../../../components/toast';
@@ -35,6 +36,11 @@ class DepartmentDetail extends React.Component {
isItemFreezed: false, isItemFreezed: false,
ancestorGroups: [], ancestorGroups: [],
members: [], members: [],
membersErrorMsg: '',
membersPageInfo: {
},
membersPage: 1,
membersPerPage: 25,
deletedMember: {}, deletedMember: {},
isShowAddMemberDialog: false, isShowAddMemberDialog: false,
showDeleteMemberDialog: false, showDeleteMemberDialog: false,
@@ -54,13 +60,15 @@ class DepartmentDetail extends React.Component {
componentDidMount() { componentDidMount() {
const groupID = this.props.groupID; const groupID = this.props.groupID;
this.listGroupRepo(groupID); this.listGroupRepo(groupID);
this.listMembers(groupID); this.getDepartmentInfo(groupID);
this.listMembers(groupID, this.state.membersPage, this.state.membersPerPage);
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (this.props.groupID !== nextProps.groupID) { if (this.props.groupID !== nextProps.groupID) {
this.listGroupRepo(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 => { seafileAPI.sysAdminGetDepartmentInfo(groupID, true).then(res => {
this.setState({ this.setState({
members: res.data.members,
groups: res.data.groups, groups: res.data.groups,
ancestorGroups: res.data.ancestor_groups, ancestorGroups: res.data.ancestor_groups,
groupName: res.data.name, 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) => { listSubDepartGroups = (groupID) => {
seafileAPI.sysAdminGetDepartmentInfo(groupID, true).then(res => { seafileAPI.sysAdminGetDepartmentInfo(groupID, true).then(res => {
this.setState({ groups: res.data.groups }); this.setState({ groups: res.data.groups });
@@ -114,7 +149,7 @@ class DepartmentDetail extends React.Component {
} }
onMemberChanged = () => { onMemberChanged = () => {
this.listMembers(this.props.groupID); this.listMembers(this.props.groupID, this.state.membersPageInfo.current_page, this.state.membersPerPage);
} }
toggleItemFreezed = (isFreezed) => { toggleItemFreezed = (isFreezed) => {
@@ -157,7 +192,7 @@ class DepartmentDetail extends React.Component {
} }
render() { render() {
const { members, repos, groups } = this.state; const { members, membersErrorMsg, repos, groups } = this.state;
const groupID = this.props.groupID; const groupID = this.props.groupID;
const topBtn = 'btn btn-secondary operation-item'; const topBtn = 'btn btn-secondary operation-item';
const topbarChildren = ( const topbarChildren = (
@@ -259,8 +294,10 @@ class DepartmentDetail extends React.Component {
<div className="fleft"><h3 className="sf-heading">{gettext('Members')}</h3></div> <div className="fleft"><h3 className="sf-heading">{gettext('Members')}</h3></div>
</div> </div>
<div className="cur-view-content"> <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> : <p className="no-member">{gettext('No members')}</p> :
<Fragment>
<table> <table>
<thead> <thead>
<tr> <tr>
@@ -287,6 +324,17 @@ class DepartmentDetail extends React.Component {
})} })}
</tbody> </tbody>
</table> </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>
</div> </div>

View File

@@ -6,6 +6,7 @@ import { siteRoot, gettext } from '../../../utils/constants';
import toaster from '../../../components/toast'; import toaster from '../../../components/toast';
import EmptyTip from '../../../components/empty-tip'; import EmptyTip from '../../../components/empty-tip';
import Loading from '../../../components/loading'; import Loading from '../../../components/loading';
import Paginator from '../../../components/paginator';
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog'; import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
import SysAdminGroupAddMemberDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-group-add-member-dialog'; import SysAdminGroupAddMemberDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-group-add-member-dialog';
import SysAdminGroupRoleEditor from '../../../components/select-editor/sysadmin-group-role-editor'; import SysAdminGroupRoleEditor from '../../../components/select-editor/sysadmin-group-role-editor';
@@ -19,8 +20,16 @@ class Content extends Component {
super(props); super(props);
} }
getPreviousPageList = () => {
this.props.getListByPage(this.props.pageInfo.current_page - 1);
}
getNextPageList = () => {
this.props.getListByPage(this.props.pageInfo.current_page + 1);
}
render() { render() {
const { loading, errorMsg, items } = this.props; const { loading, errorMsg, items, pageInfo, curPerPage } = this.props;
if (loading) { if (loading) {
return <Loading />; return <Loading />;
} else if (errorMsg) { } else if (errorMsg) {
@@ -53,6 +62,16 @@ class Content extends Component {
})} })}
</tbody> </tbody>
</table> </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> </Fragment>
); );
return items.length ? table : emptyTip; return items.length ? table : emptyTip;
@@ -148,16 +167,33 @@ class GroupMembers extends Component {
errorMsg: '', errorMsg: '',
groupName: '', groupName: '',
memberList: [], memberList: [],
pageInfo: {},
currentPage: 1,
perPage: 25,
isAddMemberDialogOpen: false isAddMemberDialogOpen: false
}; };
} }
componentDidMount () { 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({ this.setState({
loading: false, loading: false,
memberList: res.data.members, memberList: res.data.members,
groupName: res.data.group_name groupName: res.data.group_name,
pageInfo: res.data.page_info
}); });
}).catch((error) => { }).catch((error) => {
this.setState({ this.setState({
@@ -167,6 +203,14 @@ class GroupMembers extends Component {
}); });
} }
resetPerPage = (perPage) => {
this.setState({
perPage: perPage
}, () => {
this.getListByPage(1);
});
}
toggleAddMemgerDialog = () => { toggleAddMemgerDialog = () => {
this.setState({isAddMemberDialogOpen: !this.state.isAddMemberDialogOpen}); this.setState({isAddMemberDialogOpen: !this.state.isAddMemberDialogOpen});
} }
@@ -250,6 +294,10 @@ class GroupMembers extends Component {
items={this.state.memberList} items={this.state.memberList}
removeMember={this.removeMember} removeMember={this.removeMember}
updateMemberRole={this.updateMemberRole} updateMemberRole={this.updateMemberRole}
pageInfo={this.state.pageInfo}
curPerPage={this.state.perPage}
getListByPage={this.getListByPage}
resetPerPage={this.resetPerPage}
/> />
</div> </div>
</div> </div>

View File

@@ -184,20 +184,7 @@ class AdminAddressBookGroup(APIView):
for group in groups: for group in groups:
ret_groups.append(address_book_group_to_dict(group)) 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['groups'] = ret_groups
ret_dict['members'] = ret_members
if return_ancestors: if return_ancestors:
# get ancestor groups and remove last group which is self # 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) return api_error(status.HTTP_404_NOT_FOUND, error_msg)
try: try:
avatar_size = int(request.GET.get('avatar_size', avatar_size = int(request.GET.get('avatar_size', AVATAR_DEFAULT_SIZE))
AVATAR_DEFAULT_SIZE))
except ValueError: except ValueError:
avatar_size = AVATAR_DEFAULT_SIZE avatar_size = AVATAR_DEFAULT_SIZE
try: 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: except Exception as e:
logger.error(e) logger.error(e)
error_msg = 'Internal Server Error' error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 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 = [] group_members_info = []
for m in members: for m in members:
member_info = get_group_member_info(request, group_id, m.user_name, avatar_size) member_info = get_group_member_info(request, group_id, m.user_name, avatar_size)
@@ -65,9 +80,12 @@ class AdminGroupMembers(APIView):
group_members = { group_members = {
'group_id': group_id, 'group_id': group_id,
'group_name': group.group_name, '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) return Response(group_members)
def post(self, request, group_id): def post(self, request, group_id):

View File

@@ -45,13 +45,23 @@ class GroupMembers(APIView):
except ValueError: except ValueError:
avatar_size = AVATAR_DEFAULT_SIZE 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: try:
# only group member can get info of all group members # only group member can get info of all group members
if not is_group_member(group_id, request.user.username): if not is_group_member(group_id, request.user.username):
error_msg = 'Permission denied.' error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg) 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: except SearpcError as e:
logger.error(e) logger.error(e)