diff --git a/src/plus/integrations/providers/jira.ts b/src/plus/integrations/providers/jira.ts index 5ff0b34836235..96f541c6cfd83 100644 --- a/src/plus/integrations/providers/jira.ts +++ b/src/plus/integrations/providers/jira.ts @@ -12,6 +12,7 @@ import { IssueFilter, providersMetadata, toAccount, toSearchedIssue } from './mo const metadata = providersMetadata[IssueIntegrationId.Jira]; const authProvider = Object.freeze({ id: metadata.id, scopes: metadata.scopes }); +const maxPagesPerRequest = 10; export interface JiraBaseDescriptor extends ResourceDescriptor { id: string; @@ -234,16 +235,25 @@ export class JiraIntegration extends IssueIntegration { const results: SearchedIssue[] = []; for (const resource of myResources) { try { - const userLogin = (await this.getProviderAccountForResource(session, resource))?.username; - const resourceIssues = await api.getIssuesForResourceForCurrentUser(this.id, resource.id, { - accessToken: session.accessToken, - }); - const formattedIssues = resourceIssues - ?.map(issue => toSearchedIssue(issue, this, undefined, userLogin)) - .filter((result): result is SearchedIssue => result != null); - if (formattedIssues != null) { - results.push(...formattedIssues); - } + const userLogin = (await this.getProviderAccountForResource(session, resource))?.username; + let cursor = undefined; + let hasMore = false; + let requestCount = 0; + do { + const resourceIssues = await api.getIssuesForResourceForCurrentUser(this.id, resource.id, { + accessToken: session.accessToken, + cursor: cursor, + }); + requestCount += 1; + hasMore = resourceIssues.paging?.more ?? false; + cursor = resourceIssues.paging?.cursor; + const formattedIssues = resourceIssues.values + .map(issue => toSearchedIssue(issue, this, undefined, userLogin)) + .filter((result): result is SearchedIssue => result != null); + if (formattedIssues.length > 0) { + results.push(...formattedIssues); + } + } while (requestCount < maxPagesPerRequest && hasMore); } catch (ex) { // TODO: We need a better way to message the failure to the user here. // This is a stopgap to prevent one bag org from throwing and preventing any issues from being returned. diff --git a/src/plus/integrations/providers/providersApi.ts b/src/plus/integrations/providers/providersApi.ts index 8bf0aece4e289..486944b0c0c1b 100644 --- a/src/plus/integrations/providers/providersApi.ts +++ b/src/plus/integrations/providers/providersApi.ts @@ -340,7 +340,7 @@ export class ProvidersApi { } async getPagedResult( - _provider: ProviderInfo, + provider: ProviderInfo, args: any, providerFn: | (( @@ -372,27 +372,31 @@ export class ProvidersApi { ...cursorOrPage, }; - const result = await providerFn?.(input, { token: token, isPAT: usePAT }); - if (result == null) { - return { values: [] }; - } + try { + const result = await providerFn?.(input, { token: token, isPAT: usePAT }); + if (result == null) { + return { values: [] }; + } - const hasMore = result.pageInfo?.hasNextPage ?? false; + const hasMore = result.pageInfo?.hasNextPage ?? false; - let nextCursor = '{}'; - if (result.pageInfo?.endCursor != null) { - nextCursor = JSON.stringify({ value: result.pageInfo?.endCursor, type: 'cursor' }); - } else if (result.pageInfo?.nextPage != null) { - nextCursor = JSON.stringify({ value: result.pageInfo?.nextPage, type: 'page' }); - } + let nextCursor = '{}'; + if (result.pageInfo?.endCursor != null) { + nextCursor = JSON.stringify({ value: result.pageInfo?.endCursor, type: 'cursor' }); + } else if (result.pageInfo?.nextPage != null) { + nextCursor = JSON.stringify({ value: result.pageInfo?.nextPage, type: 'page' }); + } - return { - values: result.data, - paging: { - cursor: nextCursor, - more: hasMore, - }, - }; + return { + values: result.data, + paging: { + cursor: nextCursor, + more: hasMore, + }, + }; + } catch (e) { + return this.handleProviderError>(provider.id, token, e); + } } async getCurrentUser( @@ -784,24 +788,21 @@ export class ProvidersApi { async getIssuesForResourceForCurrentUser( providerId: IntegrationId, resourceId: string, - options?: { accessToken?: string }, - ): Promise { + options?: { accessToken?: string; cursor?: string }, + ): Promise> { const { provider, token } = await this.ensureProviderTokenAndFunction( providerId, 'getIssuesForResourceForCurrentUserFn', options?.accessToken, ); - try { - const result = await provider.getIssuesForResourceForCurrentUserFn?.( - { resourceId: resourceId }, - { token: token }, - ); - - return result?.data; - } catch (e) { - return this.handleProviderError(providerId, token, e); - } + return this.getPagedResult( + provider, + { resourceId: resourceId }, + provider.getIssuesForResourceForCurrentUserFn, + token, + options?.cursor, + ); } async getIssue(