diff --git a/components/dashboard/src/admin/WorkspacesSearch.tsx b/components/dashboard/src/admin/WorkspacesSearch.tsx index 74fc1a4b868748..93aabaefe8bf95 100644 --- a/components/dashboard/src/admin/WorkspacesSearch.tsx +++ b/components/dashboard/src/admin/WorkspacesSearch.tsx @@ -89,7 +89,7 @@ export function WorkspaceSearch(props: Props) { - ke.key === 'Enter' && search() } onChange={(v) => { setSearchTerm(v.target.value) }} /> + ke.key === 'Enter' && search() } onChange={(v) => { setSearchTerm(v.target.value) }} /> @@ -125,4 +125,4 @@ function WorkspaceEntry(p: { ws: WorkspaceAndInstance }) { ; -} \ No newline at end of file +} diff --git a/components/gitpod-db/src/typeorm/workspace-db-impl.ts b/components/gitpod-db/src/typeorm/workspace-db-impl.ts index 42ab7a7b8f650d..7aa8fe21450db5 100644 --- a/components/gitpod-db/src/typeorm/workspace-db-impl.ts +++ b/components/gitpod-db/src/typeorm/workspace-db-impl.ts @@ -698,14 +698,22 @@ export abstract class AbstractTypeORMWorkspaceDBImpl extends AbstractWorkspaceDB public async findAllWorkspaceAndInstances(offset: number, limit: number, orderBy: keyof WorkspaceAndInstance, orderDir: "ASC" | "DESC", ownerId?: string, searchTerm?: string): Promise<{ total: number, rows: WorkspaceAndInstance[] }> { - let joinConditions = []; - let joinConditionParams: any = {}; + let whereConditions = ['wsi2.id IS NULL']; + let whereConditionParams: any = {}; + if (!!ownerId) { - joinConditions.push("ws.ownerId = :ownerId"); - joinConditionParams.ownerId = ownerId; + // If an owner id is provided only search for workspaces belonging to that user. + whereConditions.push("ws.ownerId = :ownerId"); + whereConditionParams.ownerId = ownerId; } + if (!!searchTerm) { - joinConditions.push(`ws.contextURL LIKE '%${searchTerm}%'`); + // If a search term is provided perform a wildcard search in the context url or exact match on the workspace id (aka workspace name) or the instance id. + whereConditions.push([ + `ws.contextURL LIKE '%${searchTerm}%'`, + `ws.id = '${searchTerm}'`, + `wsi.id = '${searchTerm}'` + ].join(' OR ')) } let orderField: string = orderBy; @@ -731,7 +739,7 @@ export abstract class AbstractTypeORMWorkspaceDBImpl extends AbstractWorkspaceDB 'wsi2.workspaceId = ws.id', '(wsi.creationTime < wsi2.creationTime OR (wsi.creationTime = wsi2.creationTime AND wsi.id < wsi2.id))' ].join(' AND ')) - .where([ ... joinConditions, 'wsi2.id IS NULL' ].join(' AND '), joinConditionParams) + .where(whereConditions.join(' AND '), whereConditionParams) .orderBy(orderField, orderDir) .take(limit) .skip(offset); diff --git a/components/gitpod-db/src/workspace-db.spec.db.ts b/components/gitpod-db/src/workspace-db.spec.db.ts index f3ce4caf833225..8d5e68bf0ede16 100644 --- a/components/gitpod-db/src/workspace-db.spec.db.ts +++ b/components/gitpod-db/src/workspace-db.spec.db.ts @@ -301,5 +301,48 @@ import { DBWorkspaceInstance } from './typeorm/entity/db-workspace-instance'; expect(workspaceAndInstance.instanceId).to.eq(this.wsi2.id) }); } + + @test(timeout(10000)) + public async testFindAllWorkspaceAndInstances_workspaceId() { + await this.db.transaction(async db => { + await Promise.all([ + db.store(this.ws), + db.storeInstance(this.wsi1), + db.store(this.ws2), + db.storeInstance(this.ws2i1), + ]); + const dbResult = await db.findAllWorkspaceAndInstances(0, 10, "workspaceId", "DESC", undefined, this.ws2.id); + // It should only find one workspace instance + expect(dbResult.total).to.eq(1); + + // It should find the workspace with the queried id + const workspaceAndInstance = dbResult.rows[0] + expect(workspaceAndInstance.workspaceId).to.eq(this.ws2.id) + }); + } + + @test(timeout(10000)) + public async testFindAllWorkspaceAndInstances_instanceId() { + await this.db.transaction(async db => { + await Promise.all([ + db.store(this.ws), + db.storeInstance(this.wsi1), + db.storeInstance(this.wsi2), + db.store(this.ws2), + db.storeInstance(this.ws2i1), + ]); + const dbResult = await db.findAllWorkspaceAndInstances(0, 10, "instanceId", "DESC", undefined, this.wsi1.id); + + // It should only find one workspace instance + expect(dbResult.total).to.eq(1); + + // It should find the workspace with the queried id + const workspaceAndInstance = dbResult.rows[0] + expect(workspaceAndInstance.workspaceId).to.eq(this.ws.id) + + // It should select the workspace instance that was queried, not the most recent one + expect(workspaceAndInstance.instanceId).to.eq(this.wsi1.id) + }); + } } module.exports = new WorkspaceDBSpec()