Skip to content

Commit

Permalink
Search GitHub PR by the entered URL
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeibbb committed Oct 8, 2024
1 parent 1b62678 commit d067576
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 10 deletions.
7 changes: 6 additions & 1 deletion src/constants.telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,12 @@ export type TelemetryEvents = {
/** Sent when a launchpad operation is taking longer than a set timeout to complete */
'launchpad/operation/slow': {
timeout: number;
operation: 'getMyPullRequests' | 'getCodeSuggestions' | 'getEnrichedItems' | 'getCodeSuggestionCounts';
operation:
| 'getMyPullRequests'
| 'getCodeSuggestions'
| 'getEnrichedItems'
| 'getCodeSuggestionCounts'
| 'getPullRequest'
duration: number;
};

Expand Down
16 changes: 13 additions & 3 deletions src/plus/launchpad/launchpad.ts
Original file line number Diff line number Diff line change
Expand Up @@ -522,11 +522,12 @@ export class LaunchpadCommand extends QuickCommand<State> {

const updateItems = async (
quickpick: QuickPick<LaunchpadItemQuickPickItem | DirectiveQuickPickItem | ConnectMoreIntegrationsItem>,
search?: string,
) => {
quickpick.busy = true;

try {
await updateContextItems(this.container, context, { force: true });
await updateContextItems(this.container, context, { force: true, search: search });

const { items, placeholder } = getItemsAndPlaceholder();
quickpick.placeholder = placeholder;
Expand All @@ -552,7 +553,7 @@ export class LaunchpadCommand extends QuickCommand<State> {
LaunchpadSettingsQuickInputButton,
RefreshQuickInputButton,
],
onDidChangeValue: quickpick => {
onDidChangeValue: async quickpick => {
const hideGroups = Boolean(quickpick.value?.length);

if (groupsHidden !== hideGroups) {
Expand All @@ -576,8 +577,13 @@ export class LaunchpadCommand extends QuickCommand<State> {
// This is a hack because the quickpick doesn't update until you change the items
quickpick.items = [...quickpick.items];
}
// We have found an item that matches to the URL.
// Now it will be displayed as the found item and we exit this function now without sending any requests to API:
return true;
}
}
// Nothing is found above, so let's perform search in the API:
await updateItems(quickpick, value);
}

return true;
Expand Down Expand Up @@ -1314,7 +1320,11 @@ function getIntegrationTitle(integrationId: string): string {
}
}

async function updateContextItems(container: Container, context: Context, options?: { force?: boolean }) {
async function updateContextItems(
container: Container,
context: Context,
options?: { force?: boolean; search?: string },
) {
context.result = await container.launchpad.getCategorizedItems(options);
if (container.telemetry.enabled) {
updateTelemetryContext(context);
Expand Down
50 changes: 44 additions & 6 deletions src/plus/launchpad/launchpadProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,34 @@ export class LaunchpadProvider implements Disposable {
return { prs: prs, suggestionCounts: suggestionCounts };
}

private async getSearchedPullRequests(search: string) {
const { ownerAndRepo, prNumber } = getPullRequestIdentityValuesFromSearch(search);
let result: TimedResult<SearchedPullRequest[] | undefined> | undefined;

if (prNumber != null) {
if (ownerAndRepo != null) {
// TODO: This needs to be generalized to work outside of GitHub
const integration = await this.container.integrations.get(HostingIntegrationId.GitHub);
const [owner, repo] = ownerAndRepo.split('/', 2);
const descriptor: GitHubRepositoryDescriptor = {
key: ownerAndRepo,
owner: owner,
name: repo,
};
const pr = await withDurationAndSlowEventOnTimeout(
integration?.getPullRequest(descriptor, prNumber),
'getPullRequest',
this.container,
);
if (pr?.value != null) {
result = { value: [{ pullRequest: pr.value, reasons: [] }], duration: pr.duration };
return { prs: result, suggestionCounts: undefined };
}
}
}
return { prs: undefined, suggestionCounts: undefined };
}

private _enrichedItems: CachedLaunchpadPromise<TimedResult<EnrichedItem[]>> | undefined;
@debug<LaunchpadProvider['getEnrichedItems']>({ args: { 0: o => `force=${o?.force}` } })
private async getEnrichedItems(options?: { cancellation?: CancellationToken; force?: boolean }) {
Expand Down Expand Up @@ -612,12 +640,12 @@ export class LaunchpadProvider implements Disposable {
@gate<LaunchpadProvider['getCategorizedItems']>(o => `${o?.force ?? false}`)
@log<LaunchpadProvider['getCategorizedItems']>({ args: { 0: o => `force=${o?.force}`, 1: false } })
async getCategorizedItems(
options?: { force?: boolean },
options?: { force?: boolean; search?: string },
cancellation?: CancellationToken,
): Promise<LaunchpadCategorizedResult> {
const scope = getLogScope();

const fireRefresh = options?.force || this._prs == null;
const fireRefresh = !options?.search && (options?.force || this._prs == null);

const ignoredRepositories = new Set(
(configuration.get('launchpad.ignoredRepositories') ?? []).map(r => r.toLowerCase()),
Expand All @@ -638,7 +666,9 @@ export class LaunchpadProvider implements Disposable {
const [_, enrichedItemsResult, prsWithCountsResult] = await Promise.allSettled([
this.container.git.isDiscoveringRepositories,
this.getEnrichedItems({ force: options?.force, cancellation: cancellation }),
this.getPullRequestsWithSuggestionCounts({ force: options?.force, cancellation: cancellation }),
options?.search
? this.getSearchedPullRequests(options.search)
: this.getPullRequestsWithSuggestionCounts({ force: options?.force, cancellation: cancellation }),
]);

if (cancellation?.isCancellationRequested) throw new CancellationError();
Expand Down Expand Up @@ -752,7 +782,7 @@ export class LaunchpadProvider implements Disposable {
item.suggestedActionCategory,
)!;
// category overrides
if (staleDate != null && item.updatedDate.getTime() < staleDate.getTime()) {
if (!options?.search && staleDate != null && item.updatedDate.getTime() < staleDate.getTime()) {
actionableCategory = 'other';
} else if (codeSuggestionsCount > 0 && item.viewer.isAuthor) {
actionableCategory = 'code-suggestions';
Expand Down Expand Up @@ -788,7 +818,10 @@ export class LaunchpadProvider implements Disposable {
};
return result;
} finally {
this.updateGroupedIds(result?.items ?? []);
if (!options?.search) {
this.updateGroupedIds(result?.items ?? []);
}

if (result != null && fireRefresh) {
this._onDidRefresh.fire(result);
}
Expand Down Expand Up @@ -1040,7 +1073,12 @@ const slowEventTimeout = 1000 * 30; // 30 seconds

function withDurationAndSlowEventOnTimeout<T>(
promise: Promise<T>,
name: 'getMyPullRequests' | 'getCodeSuggestionCounts' | 'getCodeSuggestions' | 'getEnrichedItems',
name:
| 'getMyPullRequests'
| 'getCodeSuggestionCounts'
| 'getCodeSuggestions'
| 'getEnrichedItems'
| 'getPullRequest'
container: Container,
): Promise<TimedResult<T>> {
return timedWithSlowThreshold(promise, {
Expand Down

0 comments on commit d067576

Please sign in to comment.