Skip to content

Commit 1d649a7

Browse files
committed
handle pagination for ListAuthProvider(Description)s
1 parent b91164a commit 1d649a7

File tree

3 files changed

+68
-3
lines changed

3 files changed

+68
-3
lines changed

components/server/src/api/auth-provider-service-api.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
import { AuthProviderService } from "../auth/auth-provider-service";
2626
import { AuthProviderEntry, AuthProviderInfo } from "@gitpod/gitpod-protocol";
2727
import { Unauthenticated } from "./unauthenticated";
28+
import { selectPage } from "./pagination";
2829

2930
@injectable()
3031
export class AuthProviderServiceAPI implements ServiceImpl<typeof AuthProviderServiceInterface> {
@@ -98,10 +99,14 @@ export class AuthProviderServiceAPI implements ServiceImpl<typeof AuthProviderSe
9899
? await this.authProviderService.getAuthProvidersOfOrg(context.user.id, organizationId)
99100
: await this.authProviderService.getAuthProvidersOfUser(context.user.id);
100101

101-
const redacted = authProviders.map(AuthProviderEntry.redact.bind(AuthProviderEntry));
102+
const selectedProviders = selectPage(authProviders, request.pagination);
103+
const redacted = selectedProviders.map(AuthProviderEntry.redact.bind(AuthProviderEntry));
102104

103105
const result = new ListAuthProvidersResponse({
104106
authProviders: redacted.map((ap) => this.apiConverter.toAuthProvider(ap)),
107+
pagination: {
108+
total: redacted.length,
109+
},
105110
});
106111
return result;
107112
}
@@ -111,16 +116,19 @@ export class AuthProviderServiceAPI implements ServiceImpl<typeof AuthProviderSe
111116
*/
112117
@Unauthenticated()
113118
async listAuthProviderDescriptions(
114-
_request: ListAuthProviderDescriptionsRequest,
119+
request: ListAuthProviderDescriptionsRequest,
115120
context: HandlerContext,
116121
): Promise<ListAuthProviderDescriptionsResponse> {
117122
const user = context.user;
118123
const aps = user
119124
? await this.authProviderService.getAuthProviderDescriptions(user)
120125
: await this.authProviderService.getAuthProviderDescriptionsUnauthenticated();
121126

127+
const selectedProviders = selectPage(aps, request.pagination);
122128
return new ListAuthProviderDescriptionsResponse({
123-
descriptions: aps.map((ap: AuthProviderInfo) => this.apiConverter.toAuthProviderDescription(ap)),
129+
descriptions: selectedProviders.map((ap: AuthProviderInfo) =>
130+
this.apiConverter.toAuthProviderDescription(ap),
131+
),
124132
});
125133
}
126134

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import * as chai from "chai";
8+
import { selectPage, PAGE_DEFAULT, PAGE_SIZE_DEFAULT, PAGE_SIZE_MAX } from "./pagination";
9+
import { PaginationRequest } from "@gitpod/public-api/lib/gitpod/v1/pagination_pb";
10+
11+
const expect = chai.expect;
12+
13+
describe("selectPage", function () {
14+
const a1000 = Array.from({ length: 1000 }, (_, i) => `item${i + 1}`);
15+
const a10 = Array.from({ length: 10 }, (_, i) => `item${i + 1}`);
16+
17+
it(`should return first ${PAGE_SIZE_DEFAULT} if pagination is not specified`, function () {
18+
const selection = selectPage(a1000);
19+
expect(selection).to.have.lengthOf(PAGE_SIZE_DEFAULT);
20+
expect(selection[0]).to.equal(`item${PAGE_DEFAULT}`);
21+
});
22+
it(`should return first ${PAGE_SIZE_MAX} if page size exceed max`, function () {
23+
const selection = selectPage(a1000, new PaginationRequest({ pageSize: PAGE_SIZE_MAX + 1 }));
24+
expect(selection).to.have.lengthOf(PAGE_SIZE_MAX);
25+
expect(selection[0]).to.equal(`item${PAGE_DEFAULT}`);
26+
});
27+
it(`should return second page`, function () {
28+
const selection = selectPage(a1000, new PaginationRequest({ page: 2, pageSize: 50 }));
29+
expect(selection).to.have.lengthOf(50);
30+
expect(selection[0]).to.equal(`item${1 * 50 + 1}`);
31+
expect(selection[selection.length - 1]).to.equal(`item${2 * 50}`);
32+
});
33+
it(`should return all if it fits into a page`, function () {
34+
const selection = selectPage(a10, new PaginationRequest({ pageSize: 50 }));
35+
expect(selection).to.have.lengthOf(10);
36+
expect(selection[0]).to.equal(`item${1}`);
37+
expect(selection[selection.length - 1]).to.equal(`item${10}`);
38+
});
39+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { PaginationRequest } from "@gitpod/public-api/lib/gitpod/v1/pagination_pb";
8+
9+
export const PAGE_SIZE_DEFAULT = 25;
10+
export const PAGE_SIZE_MAX = 100;
11+
export const PAGE_DEFAULT = 1;
12+
13+
export function selectPage<T>(all: T[], pagination?: PaginationRequest): T[] {
14+
const page = Math.max(pagination?.page || PAGE_DEFAULT, PAGE_DEFAULT);
15+
const pageSize = Math.min(pagination?.pageSize || PAGE_SIZE_DEFAULT, PAGE_SIZE_MAX);
16+
17+
return all.slice(pageSize * (page - 1), pageSize * page);
18+
}

0 commit comments

Comments
 (0)