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:
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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
|
||||
|
@@ -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):
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user