Skip to content

Commit bacbad2

Browse files
committed
[papi] add ListWorkspaces API
1 parent bf06755 commit bacbad2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1364
-300
lines changed

components/dashboard/src/service/json-rpc-workspace-client.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@ import {
1212
GetWorkspaceResponse,
1313
WatchWorkspaceStatusRequest,
1414
WatchWorkspaceStatusResponse,
15+
ListWorkspacesRequest,
16+
ListWorkspacesRequest_Scope,
17+
ListWorkspacesResponse,
1518
} from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
1619
import { converter } from "./public-api";
1720
import { getGitpodService } from "./service";
21+
import { PaginationResponse } from "@gitpod/public-api/lib/gitpod/v1/pagination_pb";
1822
import { generateAsyncGenerator } from "@gitpod/gitpod-protocol/lib/generate-async-generator";
1923
import { WorkspaceInstance } from "@gitpod/gitpod-protocol";
2024

@@ -80,4 +84,30 @@ export class JsonRpcWorkspaceClient implements PromiseClient<typeof WorkspaceSer
8084
yield response;
8185
}
8286
}
87+
88+
async listWorkspaces(
89+
request: PartialMessage<ListWorkspacesRequest>,
90+
_options?: CallOptions,
91+
): Promise<ListWorkspacesResponse> {
92+
request.scope = request.scope ?? ListWorkspacesRequest_Scope.MY_WORKSPACES_IN_ORGANIZATION;
93+
if (
94+
request.scope === ListWorkspacesRequest_Scope.MY_WORKSPACES_IN_ORGANIZATION ||
95+
request.scope === ListWorkspacesRequest_Scope.ALL_WORKSPACES_IN_ORGANIZATION
96+
) {
97+
throw new ConnectError("organization_id is required", Code.InvalidArgument);
98+
}
99+
const server = getGitpodService().server;
100+
const pageSize = request.pagination?.pageSize || 100;
101+
const workspaces = await server.getWorkspaces({
102+
organizationId: request.organizationId,
103+
pinnedOnly: request.pinned === true ? true : undefined,
104+
limit: pageSize,
105+
offset: (request.pagination?.page ?? 0) * pageSize,
106+
});
107+
const response = new ListWorkspacesResponse();
108+
response.workspaces = workspaces.map((info) => converter.toWorkspace(info));
109+
response.pagination = new PaginationResponse();
110+
response.pagination.total = workspaces.length;
111+
return response;
112+
}
83113
}

components/dashboard/src/service/public-api.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ export const organizationClient = createServiceClient(
4646
"organization",
4747
);
4848

49+
// @ts-ignore
50+
window.$workspaceClient = workspaceClient;
51+
4952
export async function listAllProjects(opts: { orgId: string }): Promise<ProtocolProject[]> {
5053
let pagination = {
5154
page: 1,

components/gitpod-db/src/typeorm/workspace-db-impl.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ export class TypeORMWorkspaceDBImpl extends TransactionalDBImpl<WorkspaceDB> imp
177177
return this.findById(instance.workspaceId);
178178
}
179179

180-
public async find(options: FindWorkspacesOptions): Promise<WorkspaceInfo[]> {
180+
public async find(options: FindWorkspacesOptions): Promise<{ total: number; rows: WorkspaceInfo[] }> {
181181
/**
182182
* With this query we want to list all user workspaces by lastActivity and include the latestWorkspaceInstance (if present).
183183
* Implementation notes:
@@ -233,7 +233,7 @@ export class TypeORMWorkspaceDBImpl extends TransactionalDBImpl<WorkspaceDB> imp
233233
if (projectIds !== undefined) {
234234
if (projectIds.length === 0 && !options.includeWithoutProject) {
235235
// user passed an empty array of projectids and also is not interested in unassigned workspaces -> no results
236-
return [];
236+
return { total: 0, rows: [] };
237237
}
238238
qb.andWhere(
239239
new Brackets((qb) => {
@@ -251,15 +251,16 @@ export class TypeORMWorkspaceDBImpl extends TransactionalDBImpl<WorkspaceDB> imp
251251
}),
252252
);
253253
}
254-
const rawResults = (await qb.getMany()) as any as (Workspace & { latestInstance?: WorkspaceInstance })[]; // see leftJoinAndMapOne above
255-
return rawResults.map((r) => {
254+
const [rawResults, total] = await qb.getManyAndCount();
255+
const rows = (rawResults as any as (Workspace & { latestInstance?: WorkspaceInstance })[]).map((r) => {
256256
const workspace = { ...r };
257257
delete workspace.latestInstance;
258258
return {
259259
workspace,
260260
latestInstance: r.latestInstance,
261261
};
262262
});
263+
return { total, rows };
263264
}
264265

265266
public async updateLastHeartbeat(

components/gitpod-db/src/workspace-db.spec.db.ts

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -415,9 +415,9 @@ class WorkspaceDBSpec {
415415
});
416416

417417
// It should only find one workspace instance
418-
expect(dbResult.length).to.eq(1);
418+
expect(dbResult.total).to.eq(1);
419419

420-
expect(dbResult[0].workspace.id).to.eq(this.ws.id);
420+
expect(dbResult.rows[0].workspace.id).to.eq(this.ws.id);
421421
}
422422

423423
@test(timeout(10000))
@@ -437,9 +437,9 @@ class WorkspaceDBSpec {
437437
});
438438

439439
// It should only find one workspace instance
440-
expect(dbResult.length).to.eq(1);
440+
expect(dbResult.total).to.eq(1);
441441

442-
expect(dbResult[0].workspace.id).to.eq(this.ws2.id);
442+
expect(dbResult.rows[0].workspace.id).to.eq(this.ws2.id);
443443
}
444444

445445
@test(timeout(10000))
@@ -458,10 +458,10 @@ class WorkspaceDBSpec {
458458
includeWithoutProject: false,
459459
});
460460

461-
expect(dbResult.length).to.eq(2);
461+
expect(dbResult.total).to.eq(2);
462462

463-
expect(dbResult[0].workspace.id).to.eq(this.ws.id);
464-
expect(dbResult[1].workspace.id).to.eq(this.ws2.id);
463+
expect(dbResult.rows[0].workspace.id).to.eq(this.ws.id);
464+
expect(dbResult.rows[1].workspace.id).to.eq(this.ws2.id);
465465
}
466466

467467
@test(timeout(10000))
@@ -480,7 +480,7 @@ class WorkspaceDBSpec {
480480
includeWithoutProject: false,
481481
});
482482

483-
expect(dbResult.length).to.eq(0);
483+
expect(dbResult.total).to.eq(0);
484484

485485
// expect(dbResult[0].workspace.id).to.eq(this.ws.id);
486486
// expect(dbResult[1].workspace.id).to.eq(this.ws2.id);
@@ -504,9 +504,9 @@ class WorkspaceDBSpec {
504504
includeWithoutProject: true,
505505
});
506506

507-
expect(dbResult.length).to.eq(1);
507+
expect(dbResult.total).to.eq(1);
508508

509-
expect(dbResult[0].workspace.id).to.eq(this.ws3.id);
509+
expect(dbResult.rows[0].workspace.id).to.eq(this.ws3.id);
510510
}
511511

512512
@test(timeout(10000))
@@ -527,10 +527,10 @@ class WorkspaceDBSpec {
527527
includeWithoutProject: true,
528528
});
529529

530-
expect(dbResult.length).to.eq(2);
530+
expect(dbResult.total).to.eq(2);
531531

532-
expect(dbResult[0].workspace.id).to.eq(this.ws2.id);
533-
expect(dbResult[1].workspace.id).to.eq(this.ws3.id);
532+
expect(dbResult.rows[0].workspace.id).to.eq(this.ws2.id);
533+
expect(dbResult.rows[1].workspace.id).to.eq(this.ws3.id);
534534
}
535535

536536
@test(timeout(10000))
@@ -792,8 +792,8 @@ class WorkspaceDBSpec {
792792
organizationId: this.orgidA,
793793
});
794794

795-
expect(result.length).to.eq(2);
796-
for (const ws of result) {
795+
expect(result.total).to.eq(2);
796+
for (const ws of result.rows) {
797797
expect(ws.workspace.organizationId).to.equal(this.orgidA);
798798
}
799799

@@ -802,8 +802,8 @@ class WorkspaceDBSpec {
802802
organizationId: this.orgidB,
803803
});
804804

805-
expect(result.length).to.eq(1);
806-
for (const ws of result) {
805+
expect(result.total).to.eq(1);
806+
for (const ws of result.rows) {
807807
expect(ws.workspace.organizationId).to.equal(this.orgidB);
808808
}
809809

@@ -812,7 +812,7 @@ class WorkspaceDBSpec {
812812
organizationId: "no-org",
813813
});
814814

815-
expect(result.length).to.eq(0);
815+
expect(result.total).to.eq(0);
816816
}
817817

818818
@test(timeout(10000))

components/gitpod-db/src/workspace-db.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface FindWorkspacesOptions {
3232
projectId?: string | string[];
3333
includeWithoutProject?: boolean;
3434
limit?: number;
35+
offset?: number;
3536
searchString?: string;
3637
includeHeadless?: boolean;
3738
pinnedOnly?: boolean;
@@ -80,7 +81,7 @@ export interface WorkspaceDB {
8081
updatePartial(workspaceId: string, partial: DeepPartial<Workspace>): Promise<void>;
8182
findById(id: string): Promise<MaybeWorkspace>;
8283
findByInstanceId(id: string): Promise<MaybeWorkspace>;
83-
find(options: FindWorkspacesOptions): Promise<WorkspaceInfo[]>;
84+
find(options: FindWorkspacesOptions): Promise<{ total: number; rows: WorkspaceInfo[] }>;
8485
findWorkspacePortsAuthDataById(workspaceId: string): Promise<WorkspacePortsAuthData | undefined>;
8586

8687
storeInstance(instance: WorkspaceInstance): Promise<WorkspaceInstance>;

components/gitpod-protocol/src/gitpod-service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ export interface StartWorkspaceResult {
408408
export namespace GitpodServer {
409409
export interface GetWorkspacesOptions {
410410
limit?: number;
411+
offset?: number;
411412
searchString?: string;
412413
pinnedOnly?: boolean;
413414
projectId?: string | string[];
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
syntax = "proto3";
2+
3+
package gitpod.v1;
4+
5+
option go_package = "github.com/gitpod-io/gitpod/components/public-api/go/v1";
6+
7+
enum SortOrder {
8+
SORT_ORDER_UNSPECIFIED = 0;
9+
SORT_ORDER_ASCENDING = 1;
10+
SORT_ORDER_DESCENDING = 2;
11+
}

components/public-api/gitpod/v1/workspace.proto

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ syntax = "proto3";
33
package gitpod.v1;
44

55
import "google/protobuf/timestamp.proto";
6+
import "gitpod/v1/pagination.proto";
7+
import "gitpod/v1/sort.proto";
68

79
option go_package = "github.com/gitpod-io/gitpod/components/public-api/go/v1";
810

@@ -17,6 +19,9 @@ service WorkspaceService {
1719
//
1820
// workspace_id +return NOT_FOUND Workspace does not exist
1921
rpc WatchWorkspaceStatus(WatchWorkspaceStatusRequest) returns (stream WatchWorkspaceStatusResponse) {}
22+
23+
// ListWorkspaces returns a list of workspaces that match the query.
24+
rpc ListWorkspaces(ListWorkspacesRequest) returns (ListWorkspacesResponse) {}
2025
}
2126

2227
message GetWorkspaceRequest { string id = 1; }
@@ -38,6 +43,55 @@ message WatchWorkspaceStatusResponse {
3843
WorkspaceStatus status = 2;
3944
}
4045

46+
message ListWorkspacesRequest {
47+
// pagination contains the pagination options for listing workspaces
48+
PaginationRequest pagination = 1;
49+
50+
repeated WorkspaceSortRequest sorts = 2;
51+
52+
// scope of the workspaces
53+
Scope scope = 3;
54+
55+
enum Scope {
56+
SCOPE_UNSPECIFIED = 0;
57+
58+
// SCOPE_MY_WORKSPACES_IN_ORGANIZATION scopes workspaces that is owned by current user in the organization
59+
SCOPE_MY_WORKSPACES_IN_ORGANIZATION = 1;
60+
61+
// SCOPE_ALL_WORKSPACES_IN_ORGANIZATION scopes all workspaces in the organization
62+
SCOPE_ALL_WORKSPACES_IN_ORGANIZATION = 2;
63+
64+
// SCOPE_ALL_WORKSPACES_IN_INSTALLATION scopes all workspaces in the installation
65+
SCOPE_ALL_WORKSPACES_IN_INSTALLATION = 3;
66+
}
67+
68+
// organization_id is the ID of the organization that contains the workspaces
69+
string organization_id = 4;
70+
71+
// pinned indicates whether to list only pinned workspaces
72+
bool pinned = 5;
73+
74+
// search_term is a search term to filter workspaces by name
75+
string search_term = 6;
76+
}
77+
78+
message ListWorkspacesResponse {
79+
// workspaces are the workspaces that matched the query
80+
repeated Workspace workspaces = 1;
81+
82+
// pagination contains the pagination options for listing workspaces
83+
PaginationResponse pagination = 2;
84+
}
85+
86+
enum WorkspaceSortableField {
87+
WORKSPACE_SORTABLE_FIELD_UNSPECIFIED = 0;
88+
}
89+
90+
message WorkspaceSortRequest {
91+
WorkspaceSortableField field = 1;
92+
SortOrder order = 2;
93+
}
94+
4195
// +resource get workspace
4296
message Workspace {
4397
string id = 1;

0 commit comments

Comments
 (0)