Skip to content

Commit 0445e12

Browse files
committed
feat(UserList): add users per page selector
works with changes in ibi-group/datatools-server#353
1 parent f58878c commit 0445e12

File tree

5 files changed

+66
-16
lines changed

5 files changed

+66
-16
lines changed

i18n/english.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ components:
764764
UserList:
765765
filterByOrg: Filter by org.
766766
of: of
767+
perPage: Users per page
767768
search: Search by username
768769
showing: Showing Users
769770
title: User Management

lib/admin/actions/admin.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// @flow
22

33
import {createAction, type ActionType} from 'redux-actions'
4+
import qs from 'qs'
45

56
import {createVoidPayloadAction, secureFetch} from '../../common/actions'
67
import {setErrorMessage} from '../../manager/actions/status'
@@ -47,6 +48,10 @@ export const setUserPage = createAction(
4748
'SET_USER_PAGE',
4849
(payload: number) => payload
4950
)
51+
export const setUserPerPage = createAction(
52+
'SET_USER_PER_PAGE',
53+
(payload: number) => payload
54+
)
5055
export const setUserQueryString = createAction(
5156
'SET_USER_QUERY_STRING',
5257
(payload: string) => payload
@@ -56,6 +61,7 @@ export type AdminActions = ActionType<typeof createdUser> |
5661
ActionType<typeof receiveUsers> |
5762
ActionType<typeof requestingUsers> |
5863
ActionType<typeof setUserPage> |
64+
ActionType<typeof setUserPerPage> |
5965
ActionType<typeof setUserQueryString> |
6066
ActionType<typeof deleteServer> |
6167
ActionType<typeof fetchServers> |
@@ -64,17 +70,15 @@ export type AdminActions = ActionType<typeof createdUser> |
6470
export function fetchUsers () {
6571
return function (dispatch: dispatchFn, getState: getStateFn) {
6672
dispatch(requestingUsers())
67-
const queryString = getState().admin.users.userQueryString
68-
73+
const {page, perPage, userQueryString: queryString} = getState().admin.users
6974
let countUrl = '/api/manager/secure/usercount'
70-
if (queryString) countUrl += `?queryString=${queryString}`
75+
if (queryString) countUrl += `?${qs.stringify({queryString})}`
7176
const getCount = dispatch(secureFetch(countUrl))
72-
.then(response => response.json())
73-
74-
let usersUrl = `/api/manager/secure/user?page=${getState().admin.users.page}`
75-
if (queryString) usersUrl += `&queryString=${queryString}`
77+
.then(res => res.json())
78+
const params = queryString ? {page, perPage, queryString} : {page, perPage}
79+
const usersUrl = `/api/manager/secure/user?${qs.stringify(params)}`
7680
const getUsers = dispatch(secureFetch(usersUrl))
77-
.then(response => response.json())
81+
.then(res => res.json())
7882

7983
Promise.all([getCount, getUsers]).then((results) => {
8084
if (Array.isArray(results[1])) {

lib/admin/components/UserList.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,19 @@
33
import Icon from '@conveyal/woonerf/components/icon'
44
import React, {Component} from 'react'
55
import {connect} from 'react-redux'
6-
import {Panel, Row, Col, Button, ButtonGroup, InputGroup, FormControl, ListGroup, ListGroupItem} from 'react-bootstrap'
6+
import {
7+
Panel,
8+
Row,
9+
Col,
10+
Button,
11+
ButtonGroup,
12+
DropdownButton,
13+
InputGroup,
14+
FormControl,
15+
ListGroup,
16+
ListGroupItem,
17+
MenuItem
18+
} from 'react-bootstrap'
719

820
import * as adminActions from '../actions/admin'
921
import {getComponentMessages} from '../../common/util/config'
@@ -27,6 +39,7 @@ type Props = {
2739
perPage: number,
2840
projects: Array<Project>,
2941
setUserPage: typeof adminActions.setUserPage,
42+
setUserPerPage: typeof adminActions.setUserPerPage,
3043
setUserQueryString: typeof adminActions.setUserQueryString,
3144
token: string,
3245
updateUserData: typeof managerUserActions.updateUserData,
@@ -75,6 +88,12 @@ class UserList extends Component<Props, State> {
7588
fetchUsers()
7689
}
7790

91+
_setUserPerPage = (perPage: number) => {
92+
const {fetchUsers, setUserPerPage} = this.props
93+
setUserPerPage(perPage)
94+
fetchUsers()
95+
}
96+
7897
_userSearch = () => {
7998
const {fetchUsers, setUserPage, setUserQueryString} = this.props
8099
setUserPage(0)
@@ -132,6 +151,21 @@ class UserList extends Component<Props, State> {
132151
</span>
133152
: <span style={headerStyle}>(No results to show)</span>
134153
}
154+
<div className='pull-right'>
155+
{this.messages('perPage')}{' '}
156+
<DropdownButton
157+
id='per-page-dropdown'
158+
title={perPage}
159+
onSelect={this._setUserPerPage}>
160+
{// Render users per page options.
161+
[10, 25, 50, 100].map(val =>
162+
<MenuItem key={`option-${val}`} eventKey={val}>
163+
{val} {val === perPage ? <Icon type='check' /> : null}
164+
</MenuItem>
165+
)
166+
}
167+
</DropdownButton>
168+
</div>
135169
</Col>
136170
</Row>
137171
<Panel
@@ -238,6 +272,7 @@ const {
238272
deleteUser,
239273
fetchUsers,
240274
setUserPage,
275+
setUserPerPage,
241276
setUserQueryString
242277
} = adminActions
243278

@@ -247,6 +282,7 @@ const mapDispatchToProps = {
247282
fetchProjectFeeds,
248283
fetchUsers,
249284
setUserPage,
285+
setUserPerPage,
250286
setUserQueryString,
251287
updateUserData
252288
}

lib/admin/components/UserRow.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ export default class UserRow extends Component<Props, State> {
4545
this.toggleExpansion()
4646
}
4747

48+
_getOrgLabel = (permissions: UserPermissions) => {
49+
const {creatingUser, organizations} = this.props
50+
if (!organizations) return null
51+
const userOrganization = organizations.find(o => o.id === permissions.getOrganizationId())
52+
const creatorIsApplicationAdmin = creatingUser.permissions &&
53+
creatingUser.permissions.isApplicationAdmin()
54+
return userOrganization && creatorIsApplicationAdmin
55+
? <BsLabel bsStyle='default'>{userOrganization.name}</BsLabel>
56+
: null
57+
}
58+
4859
/**
4960
* Constructs label indicating user authorization level (e.g., app/org admin)
5061
* or listing the projects the user has access to.
@@ -127,7 +138,6 @@ export default class UserRow extends Component<Props, State> {
127138
const permissions = new UserPermissions(user.app_metadata && user.app_metadata.datatools)
128139
const creatorIsApplicationAdmin = creatingUser.permissions &&
129140
creatingUser.permissions.isApplicationAdmin()
130-
const userOrganization = organizations.find(o => o.id === permissions.getOrganizationId())
131141
const creatorDoesNotHaveOrg = !creatingUser.permissions ||
132142
// $FlowFixMe
133143
!creatingUser.permissions.hasOrganization(permissions.getOrganizationId())
@@ -152,10 +162,7 @@ export default class UserRow extends Component<Props, State> {
152162
{user.email}{' '}
153163
{this._getUserPermissionLabel(permissions)}
154164
{' '}
155-
{userOrganization && creatorIsApplicationAdmin
156-
? <BsLabel bsStyle='default'>{userOrganization.name}</BsLabel>
157-
: null
158-
}
165+
{this._getOrgLabel(permissions)}
159166
</h5>
160167
<small />
161168
</Col>

lib/admin/reducers/users.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import type {Action} from '../../types/actions'
66
import type {AdminUsersState} from '../../types/reducers'
77

88
export const defaultState = {
9-
isFetching: false,
109
data: null,
11-
userCount: 0,
10+
isFetching: false,
1211
page: 0,
1312
perPage: 10,
13+
userCount: 0,
1414
userQueryString: null
1515
}
1616

@@ -32,6 +32,8 @@ const users = (state: AdminUsersState = defaultState, action: Action): AdminUser
3232
return state
3333
case 'SET_USER_PAGE':
3434
return update(state, {page: { $set: action.payload }})
35+
case 'SET_USER_PER_PAGE':
36+
return update(state, {perPage: { $set: action.payload }})
3537
case 'SET_USER_QUERY_STRING':
3638
return update(state, {userQueryString: { $set: action.payload }})
3739
default:

0 commit comments

Comments
 (0)