From 949808f400f0ce44c3b325d47309e7b66736a2a2 Mon Sep 17 00:00:00 2001 From: PostHog Code Date: Sun, 10 May 2026 08:14:24 +0000 Subject: [PATCH] fix(mobile): paginate github_repos to show all repositories The mobile task creation flow called the team-level github_repos endpoint without pagination, so the repository picker capped at the backend's default page size of 100. PostHog orgs with more than 100 repositories in their GitHub App installation (e.g. PostHog itself) had repos like billing and charts truncated from the dropdown depending on cache order. Mirror the desktop client's pagination loop: request 500 at a time and follow has_more until the cache is exhausted. Generated-By: PostHog Code Task-Id: d6c191a5-70f9-4b82-b797-ef739b2b1f16 --- apps/mobile/src/features/tasks/api.ts | 61 ++++++++++++++++++--------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/apps/mobile/src/features/tasks/api.ts b/apps/mobile/src/features/tasks/api.ts index e86fcdd5c..f88901ec4 100644 --- a/apps/mobile/src/features/tasks/api.ts +++ b/apps/mobile/src/features/tasks/api.ts @@ -460,6 +460,8 @@ export async function getIntegrations(): Promise { return data.results ?? data ?? []; } +const GITHUB_REPOS_PAGE_SIZE = 500; + export async function getGithubRepositories( integrationId: number, ): Promise { @@ -467,27 +469,44 @@ export async function getGithubRepositories( const projectId = getProjectId(); const headers = getHeaders(); - const response = await fetch( - `${baseUrl}/api/environments/${projectId}/integrations/${integrationId}/github_repos/`, - { headers }, - ); - - if (!response.ok) { - throw new HttpError( - response.status, - response.statusText, - "Failed to fetch repositories", + const allRepos: string[] = []; + let offset = 0; + + while (true) { + const params = new URLSearchParams({ + limit: String(GITHUB_REPOS_PAGE_SIZE), + offset: String(offset), + }); + const response = await fetch( + `${baseUrl}/api/environments/${projectId}/integrations/${integrationId}/github_repos/?${params}`, + { headers }, ); - } - const data = await response.json(); - const repos: Array = - data.repositories ?? data.results ?? data ?? []; - - return repos - .map((repo) => { - if (typeof repo === "string") return repo.toLowerCase(); - return (repo.full_name ?? repo.name ?? "").toLowerCase(); - }) - .filter((name) => name.length > 0); + if (!response.ok) { + throw new HttpError( + response.status, + response.statusText, + "Failed to fetch repositories", + ); + } + + const data = await response.json(); + const repos: Array = + data.repositories ?? data.results ?? data ?? []; + + const normalized = repos + .map((repo) => { + if (typeof repo === "string") return repo.toLowerCase(); + return (repo.full_name ?? repo.name ?? "").toLowerCase(); + }) + .filter((name) => name.length > 0); + + allRepos.push(...normalized); + + if (!data.has_more || repos.length === 0) { + return allRepos; + } + + offset += repos.length; + } }