Skip to content

Commit 6d767e5

Browse files
committed
Enable search on staff table
1 parent bc20391 commit 6d767e5

File tree

5 files changed

+59
-29
lines changed

5 files changed

+59
-29
lines changed

cypress/e2e/organizations/pagination.cy.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ describe('Organization page', () => {
7979
cy.get('[data-cy=org-staff-table-pagination]').within(() => {
8080
cy.contains('Showing 1-3 of 3')
8181
})
82+
83+
// Perform search by username
84+
cy.get('[data-cy=org-staff-table-search-input]').type('2')
85+
cy.get('[data-cy=org-staff-table-search-submit]').click()
86+
cy.get('[data-cy=org-staff-table-pagination]').contains('Showing 1-1 of 1')
8287
})
8388

8489
it('Organization teams and members tables are populated and paginated', () => {
@@ -185,7 +190,7 @@ describe('Organization page', () => {
185190
// Item from page 2 is present
186191
cy.get('[data-cy=org-members-table]').contains('User 207')
187192

188-
// Add search term
193+
// Perform search by username
189194
cy.get('[data-cy=org-members-table-search-input]').type('User 2')
190195
cy.get('[data-cy=org-members-table-search-submit]').click()
191196
cy.get('[data-cy=org-members-table-pagination]').contains(

src/models/organization.js

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const db = require('../lib/db')
22
const team = require('./team')
3-
const { map, prop, includes, has, isNil, propEq, find } = require('ramda')
3+
const { map, prop, includes, has, isNil } = require('ramda')
44
const { unpack, PropertyRequiredError } = require('../../app/lib/utils')
55
const { serverRuntimeConfig } = require('../../next.config')
66
const { DEFAULT_PAGE_SIZE } = serverRuntimeConfig
@@ -91,6 +91,9 @@ async function create(data, osmId) {
9191

9292
if (!data.name) throw new Error('data.name property is required')
9393

94+
// Cache username
95+
await team.resolveMemberNames([osmId])
96+
9497
return db.transaction(async (trx) => {
9598
const [row] = await trx('organization')
9699
.insert(data)
@@ -186,6 +189,9 @@ async function removeOwner(id, osmId) {
186189
* @return {promise}
187190
*/
188191
async function addManager(id, osmId) {
192+
// Cache username
193+
await team.resolveMemberNames([osmId])
194+
189195
const isAlreadyManager = await isManager(id, osmId)
190196

191197
// Only ids that are not already in manager list should be added. Duplicate requests should fail silently
@@ -232,6 +238,9 @@ async function removeManager(id, osmId) {
232238
* @return {promise}
233239
*/
234240
async function createOrgTeam(organizationId, data, osmId) {
241+
// Cache username
242+
await team.resolveMemberNames([osmId])
243+
235244
return db.transaction(async (trx) => {
236245
const record = await team.create(data, osmId, trx)
237246
await trx('organization_team').insert({
@@ -438,44 +447,54 @@ async function getOrgStaff(options) {
438447
async function getOrgStaffPaginated(organizationId, options = {}) {
439448
// Get owners
440449
let ownerQuery = db('organization_owner')
441-
.select(db.raw("organization_id, osm_id, 'owner' as type"))
442-
.where('organization_id', organizationId)
450+
.join('osm_users', 'organization_owner.osm_id', 'osm_users.id')
451+
.select(
452+
'organization_owner.organization_id',
453+
'organization_owner.osm_id',
454+
db.raw("'owner' as type"),
455+
'osm_users.name'
456+
)
457+
.where('organization_owner.organization_id', organizationId)
458+
459+
// Apply search to owners sub-query
460+
if (options.search) {
461+
ownerQuery = ownerQuery.whereILike('osm_users.name', `%${options.search}%`)
462+
}
443463

444464
// Get managers that are not owners
445465
let managerQuery = db('organization_manager')
446-
.select(db.raw("organization_id, osm_id, 'manager' as type"))
447-
.where('organization_id', organizationId)
466+
.join('osm_users', 'organization_manager.osm_id', 'osm_users.id')
467+
.select(
468+
'organization_manager.organization_id',
469+
'organization_manager.osm_id',
470+
db.raw("'manager' as type"),
471+
'osm_users.name'
472+
)
473+
.where('organization_manager.organization_id', organizationId)
448474
.whereNotIn(
449-
'osm_id',
475+
'organization_manager.osm_id',
450476
db('organization_owner')
451-
.select('osm_id')
477+
.select('organization_owner.osm_id')
452478
.where('organization_id', organizationId)
453479
)
454480

455-
// Execute query with pagination
456-
const result = await ownerQuery.unionAll(managerQuery).paginate({
481+
// Apply search managers sub-query
482+
if (options.search) {
483+
managerQuery = managerQuery.whereILike(
484+
'osm_users.name',
485+
`%${options.search}%`
486+
)
487+
}
488+
489+
// Unite owner and manager queries
490+
let staffQuery = ownerQuery.unionAll(managerQuery)
491+
492+
// Execute staff query with pagination
493+
return await staffQuery.paginate({
457494
isLengthAware: true,
458495
currentPage: options.page || 1,
459496
perPage: options.perPage || DEFAULT_PAGE_SIZE,
460497
})
461-
462-
// Get osm user meta from ids
463-
const osmUsers = await team.resolveMemberNames(
464-
result.data.map((m) => m.osm_id)
465-
)
466-
467-
return {
468-
...result,
469-
// Apply OSM display names to results
470-
data: result.data.map((u) => {
471-
const osmUser = find(propEq('id', u.osm_id))(osmUsers)
472-
return {
473-
...u,
474-
id: u.osm_id,
475-
name: osmUser?.name || '',
476-
}
477-
}),
478-
}
479498
}
480499

481500
/**

src/models/team.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,9 @@ async function create(data, osmId, trx) {
344344
})
345345
}
346346

347+
// Cache username
348+
await resolveMemberNames([osmId])
349+
347350
return conn.transaction(async (trx) => {
348351
const [row] = await trx('team')
349352
.insert(data)

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,16 @@ handler.get(
4040
orgId: Yup.number().required().positive().integer().required(),
4141
page: Yup.number().min(0).integer(),
4242
perPage: Yup.number().min(1).max(100).integer(),
43+
search: Yup.string(),
4344
}).required(),
4445
}),
4546
async function (req, res) {
46-
const { orgId, page, perPage } = req.query
47+
const { orgId, page, perPage, search } = req.query
4748

4849
const staff = await Organization.getOrgStaffPaginated(orgId, {
4950
page,
5051
perPage,
52+
search,
5153
})
5254

5355
return res.send(staff)

src/pages/organizations/[id]/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ class Organization extends Component {
373373
</div>
374374
</Section>
375375
<UsersTable
376+
isSearchable
376377
type='org-staff'
377378
orgId={org.data.id}
378379
onRowClick={(row) => this.openProfileModal(row)}

0 commit comments

Comments
 (0)