fix(workspaces): add filtering to workspace team query (#2586)

* chore(workspaces): add some tests for new filters

* fix(workspaces): args style
This commit is contained in:
Chuck Driesler
2024-08-08 06:15:55 +01:00
committed by GitHub
parent 72017c3f2f
commit 7bb40134eb
9 changed files with 179 additions and 45 deletions
@@ -35,15 +35,23 @@ export type DeleteWorkspace = (args: DeleteWorkspaceArgs) => Promise<void>
/** Workspace Roles */
export type GetWorkspaceCollaborators = (args: {
type GetWorkspaceCollaboratorsArgs = {
workspaceId: string
/**
* Optionally filter by role
*/
role?: WorkspaceRoles
}) => Promise<
Array<UserWithRole<LimitedUserRecord> & { workspaceRole: WorkspaceRoles }>
>
filter?: {
/**
* Optionally filter by workspace role
*/
role?: string
/**
* Optionally filter by user name or email
*/
search?: string
}
}
export type GetWorkspaceCollaborators = (
args: GetWorkspaceCollaboratorsArgs
) => Promise<Array<UserWithRole<LimitedUserRecord> & { workspaceRole: WorkspaceRoles }>>
type DeleteWorkspaceRoleArgs = {
workspaceId: string
@@ -72,7 +72,7 @@ import {
queryAllWorkspaceProjectsFactory
} from '@/modules/workspaces/services/projects'
import { getWorkspacesForUserFactory } from '@/modules/workspaces/services/retrieval'
import { Roles, WorkspaceRoles } from '@speckle/shared'
import { Roles, WorkspaceRoles, removeNullOrUndefinedKeys } from '@speckle/shared'
import { chunk } from 'lodash'
import { deleteStream } from '@/modules/core/repositories/streams'
@@ -426,10 +426,11 @@ export = FF_WORKSPACES_MODULE_ENABLED
const workspace = await ctx.loaders.workspaces!.getWorkspace.load(parent.id)
return workspace?.role || null
},
team: async (parent) => {
team: async (parent, args) => {
const getTeam = getWorkspaceCollaboratorsFactory({ db })
const collaborators = await getTeam({
workspaceId: parent.id
workspaceId: parent.id,
filter: removeNullOrUndefinedKeys(args?.filter ?? {})
})
return collaborators
@@ -168,9 +168,7 @@ export const upsertWorkspaceRoleFactory =
export const getWorkspaceCollaboratorsFactory =
({ db }: { db: Knex }): GetWorkspaceCollaborators =>
async (params: { workspaceId: string; role?: WorkspaceRoles }) => {
const { workspaceId, role } = params
async ({ workspaceId, filter = {} }) => {
const query = DbWorkspaceAcl.knex(db)
.select<Array<UserWithRole & { workspaceRole: WorkspaceRoles }>>([
...Users.cols,
@@ -182,6 +180,14 @@ export const getWorkspaceCollaboratorsFactory =
.innerJoin(ServerAcl.name, ServerAcl.col.userId, Users.col.id)
.groupBy(Users.col.id, DbWorkspaceAcl.col.role)
const { search, role } = filter || {}
if (search) {
query
.where(Users.col.name, 'ILIKE', `%${search}%`)
.orWhere(Users.col.email, 'ILIKE', `%${search}%`)
}
if (role) {
query.andWhere(DbWorkspaceAcl.col.role, role)
}
@@ -17,11 +17,11 @@ import {
DeleteWorkspaceDocument,
GetActiveUserWorkspacesDocument,
GetWorkspaceDocument,
GetWorkspaceTeamDocument,
UpdateWorkspaceDocument,
ActiveUserLeaveWorkspaceDocument,
UpdateWorkspaceRoleDocument
UpdateWorkspaceRoleDocument,
ActiveUserLeaveWorkspaceDocument
} from '@/test/graphql/generated/graphql'
import { Workspace } from '@/modules/workspacesCore/domain/types'
import { beforeEachContext } from '@/test/hooks'
import { AllScopes } from '@/modules/core/helpers/mainConstants'
import {
@@ -66,29 +66,35 @@ describe('Workspaces GQL CRUD', () => {
})
describe('retrieval operations', () => {
const workspaceIds: string[] = []
const workspace: BasicTestWorkspace = {
id: '',
ownerId: '',
name: 'Workspace A'
}
const testMemberUser: BasicTestUser = {
id: '',
name: 'Jimmy Speckle',
email: 'jimmy-speckle@example.org'
}
before(async () => {
const workspaces: Pick<Workspace, 'name'>[] = [
{ name: 'Workspace A' },
{ name: 'Workspace B' }
]
await createTestWorkspace(workspace, testUser)
await createTestUser(testMemberUser)
const results = await Promise.all(
workspaces.map((workspace) =>
apollo.execute(CreateWorkspaceDocument, { input: workspace })
)
)
for (const result of results) {
workspaceIds.push(result.data!.workspaceMutations.create.id)
}
await apollo.execute(UpdateWorkspaceRoleDocument, {
input: {
userId: testMemberUser.id,
workspaceId: workspace.id,
role: Roles.Workspace.Member
}
})
})
describe('query workspace', () => {
it('should return a workspace that exists', async () => {
const res = await apollo.execute(GetWorkspaceDocument, {
workspaceId: workspaceIds[0]
workspaceId: workspace.id
})
expect(res).to.not.haveGraphQLErrors()
@@ -103,12 +109,46 @@ describe('Workspaces GQL CRUD', () => {
})
})
describe('query workspace.team', () => {
it('should return workspace members', async () => {
const res = await apollo.execute(GetWorkspaceTeamDocument, {
workspaceId: workspace.id
})
expect(res).to.not.haveGraphQLErrors()
expect(res.data?.workspace.team.length).to.equal(2)
})
it('should respect search filters', async () => {
const res = await apollo.execute(GetWorkspaceTeamDocument, {
workspaceId: workspace.id,
filter: {
search: 'jimmy'
}
})
expect(res).to.not.haveGraphQLErrors()
expect(res.data?.workspace.team.length).to.equal(1)
})
it('should respect role filters', async () => {
const res = await apollo.execute(GetWorkspaceTeamDocument, {
workspaceId: workspace.id,
filter: {
role: 'workspace:member'
}
})
expect(res).to.not.haveGraphQLErrors()
expect(res.data?.workspace.team.length).to.equal(1)
})
})
describe('query activeUser.workspaces', () => {
it('should return all workspaces for a user', async () => {
const res = await apollo.execute(GetActiveUserWorkspacesDocument, {})
expect(res).to.not.haveGraphQLErrors()
expect(res.data?.activeUser?.workspaces?.items?.length).to.above(1)
expect(res.data?.activeUser?.workspaces?.items?.length).to.equal(1)
})
})
})