Skip to content

Commit c62fe1e

Browse files
committed
Add sort and search to org teams list
1 parent d051728 commit c62fe1e

File tree

4 files changed

+74
-13
lines changed

4 files changed

+74
-13
lines changed

cypress/e2e/organizations/pagination.cy.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,25 @@ describe('Organization page', () => {
128128
*/
129129
cy.get('[data-cy=org-teams-table]').contains('Org 1 Team 010')
130130

131+
// Sort by name
132+
cy.get('[data-cy=org-teams-table-head-column-name]').click()
133+
cy.get('[data-cy=org-teams-table]')
134+
.find('tbody tr:nth-child(4) td:nth-child(1)')
135+
.contains('Team 032')
136+
137+
// Reset sort
138+
cy.get('[data-cy=org-teams-table-head-column-name]').click()
139+
140+
// Perform search by username
141+
cy.get('[data-cy=org-teams-table-search-input]').type('02')
142+
cy.get('[data-cy=org-teams-table-search-submit]').click()
143+
cy.get('[data-cy=org-teams-table-pagination]').contains(
144+
'Showing 1-10 of 11'
145+
)
146+
cy.get('[data-cy=org-teams-table]')
147+
.find('tbody tr:nth-child(9) td:nth-child(1)')
148+
.contains('Team 027')
149+
131150
// Verify index, then click on last page button
132151
cy.get('[data-cy=org-teams-table-pagination]').within(() => {
133152
cy.contains('Showing 1-10 of 35')
@@ -196,7 +215,7 @@ describe('Organization page', () => {
196215
// Item from page 2 is present
197216
cy.get('[data-cy=org-members-table]').contains('User 207')
198217

199-
// Sort by team name
218+
// Sort by user name
200219
cy.get('[data-cy=org-members-table-head-column-name]').click()
201220
cy.get('[data-cy=org-members-table]')
202221
.find('tbody tr:nth-child(4) td:nth-child(1)')

src/components/tables/teams.js

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,25 @@ import join from 'url-join'
55
import { useFetchList } from '../../hooks/use-fetch-list'
66
import { useState } from 'react'
77
import Pagination from '../pagination'
8+
import SearchInput from './search-input'
9+
import qs from 'qs'
810

911
const APP_URL = process.env.APP_URL
1012

1113
function TeamsTable({ type, orgId }) {
1214
const [page, setPage] = useState(1)
15+
const [search, setSearch] = useState(null)
16+
const [sort, setSort] = useState({
17+
key: 'name',
18+
direction: 'asc',
19+
})
20+
21+
const querystring = qs.stringify({
22+
search,
23+
page,
24+
sort: sort.key,
25+
order: sort.direction,
26+
})
1327

1428
let apiBasePath
1529
let emptyMessage
@@ -33,22 +47,32 @@ function TeamsTable({ type, orgId }) {
3347
const {
3448
result: { data, pagination },
3549
isLoading,
36-
} = useFetchList(`${apiBasePath}?page=${page}`)
50+
} = useFetchList(`${apiBasePath}?${querystring}`)
3751

38-
const columns = [{ key: 'name' }, { key: 'members' }]
52+
const columns = [
53+
{ key: 'name', sortable: true },
54+
{ key: 'members', sortable: true },
55+
]
3956

4057
return (
4158
<>
59+
<SearchInput
60+
data-cy={`${type}-table`}
61+
onSearch={(search) => {
62+
// Reset to page 1 and search
63+
setPage(1)
64+
setSearch(search)
65+
}}
66+
/>
4267
<Table
4368
data-cy={`${type}-table`}
4469
rows={data}
4570
columns={columns}
4671
emptyPlaceHolder={isLoading ? 'Loading...' : emptyMessage}
72+
sort={sort}
73+
setSort={setSort}
4774
onRowClick={(row) => {
48-
Router.push(
49-
join(APP_URL, `/team?id=${row.id}`),
50-
join(APP_URL, `/teams/${row.id}`)
51-
)
75+
Router.push(join(APP_URL, `/teams/${row.id}`))
5276
}}
5377
/>
5478
{pagination?.total > 0 && (

src/models/team.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,12 @@ async function count({ organizationId }) {
197197
* @return {Promise[Array]}
198198
**/
199199
async function paginatedList(options = {}) {
200-
const { bbox, osmId, organizationId, page, includePrivate } = options
200+
const currentPage = options?.page || 1
201+
const sort = options?.sort || 'name'
202+
const order = options?.order || 'asc'
203+
const perPage = options?.perPage || DEFAULT_PAGE_SIZE
204+
205+
const { bbox, osmId, organizationId, includePrivate } = options
201206
const st = knexPostgis(db)
202207

203208
let query = db('team').select(
@@ -206,6 +211,11 @@ async function paginatedList(options = {}) {
206211
db('member').count().whereRaw('team.id = member.team_id').as('members')
207212
)
208213

214+
// Apply search
215+
if (options.search) {
216+
query = query.whereILike('name', `%${options.search}%`)
217+
}
218+
209219
if (!includePrivate) {
210220
query.where('privacy', 'public')
211221
}
@@ -230,13 +240,13 @@ async function paginatedList(options = {}) {
230240
)
231241
}
232242

233-
// Always sort by team name
234-
query = query.orderBy('name')
243+
// Apply sort
244+
query = query.orderBy(sort, order)
235245

236246
return query.paginate({
237247
isLengthAware: true,
238-
currentPage: page || 1,
239-
perPage: DEFAULT_PAGE_SIZE,
248+
currentPage,
249+
perPage,
240250
})
241251
}
242252

src/pages/api/organizations/[orgId]/teams.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,25 @@ handler.get(
9696
query: Yup.object({
9797
orgId: Yup.number().required().positive().integer(),
9898
page: Yup.number().min(0).integer(),
99+
perPage: Yup.number().min(1).max(100).integer(),
100+
search: Yup.string(),
101+
sort: Yup.mixed().oneOf(['name', 'members']),
102+
order: Yup.mixed().oneOf(['asc', 'desc']),
99103
}).required(),
100104
}),
101105
async function (req, res) {
102-
const { orgId, page } = req.query
106+
const { orgId, page, perPage, search, sort, order } = req.query
103107
const {
104108
org: { isMember, isOwner, isManager },
105109
} = req
106110
return res.send(
107111
await Team.paginatedList({
108112
organizationId: orgId,
109113
page,
114+
perPage,
115+
search,
116+
sort,
117+
order,
110118
includePrivate: isMember || isManager || isOwner,
111119
})
112120
)

0 commit comments

Comments
 (0)